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
40 #include "arguments.h"
42 #include "compilation-cache.h"
43 #include "cpu-profiler.h"
44 #include "execution.h"
50 #include "unicode-inl.h"
54 static const bool kLogThreading = false;
56 using ::v8::AccessorInfo;
57 using ::v8::Arguments;
59 using ::v8::BooleanObject;
61 using ::v8::Extension;
63 using ::v8::FunctionTemplate;
65 using ::v8::HandleScope;
68 using ::v8::MessageCallback;
70 using ::v8::ObjectTemplate;
71 using ::v8::Persistent;
73 using ::v8::StackTrace;
76 using ::v8::Undefined;
82 #define THREADED_PROFILED_TEST(Name) \
83 static void Test##Name(); \
84 TEST(Name##WithProfiler) { \
85 RunWithProfiler(&Test##Name); \
89 void RunWithProfiler(void (*test)()) {
91 v8::HandleScope scope(env->GetIsolate());
92 v8::Local<v8::String> profile_name = v8::String::New("my_profile1");
93 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
95 cpu_profiler->StartCpuProfiling(profile_name);
97 cpu_profiler->DeleteAllCpuProfiles();
101 static void ExpectString(const char* code, const char* expected) {
102 Local<Value> result = CompileRun(code);
103 CHECK(result->IsString());
104 String::Utf8Value utf8(result);
105 CHECK_EQ(expected, *utf8);
109 static void ExpectInt32(const char* code, int expected) {
110 Local<Value> result = CompileRun(code);
111 CHECK(result->IsInt32());
112 CHECK_EQ(expected, result->Int32Value());
116 static void ExpectBoolean(const char* code, bool expected) {
117 Local<Value> result = CompileRun(code);
118 CHECK(result->IsBoolean());
119 CHECK_EQ(expected, result->BooleanValue());
123 static void ExpectTrue(const char* code) {
124 ExpectBoolean(code, true);
128 static void ExpectFalse(const char* code) {
129 ExpectBoolean(code, false);
133 static void ExpectObject(const char* code, Local<Value> expected) {
134 Local<Value> result = CompileRun(code);
135 CHECK(result->Equals(expected));
139 static void ExpectUndefined(const char* code) {
140 Local<Value> result = CompileRun(code);
141 CHECK(result->IsUndefined());
145 static int signature_callback_count;
146 static void IncrementingSignatureCallback(
147 const v8::FunctionCallbackInfo<v8::Value>& args) {
148 ApiTestFuzzer::Fuzz();
149 signature_callback_count++;
150 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
151 for (int i = 0; i < args.Length(); i++)
152 result->Set(v8::Integer::New(i), args[i]);
153 args.GetReturnValue().Set(result);
157 static void SignatureCallback(
158 const v8::FunctionCallbackInfo<v8::Value>& args) {
159 ApiTestFuzzer::Fuzz();
160 v8::Handle<v8::Array> result = v8::Array::New(args.Length());
161 for (int i = 0; i < args.Length(); i++) {
162 result->Set(v8::Integer::New(i), args[i]);
164 args.GetReturnValue().Set(result);
168 THREADED_TEST(Handles) {
169 v8::HandleScope scope(v8::Isolate::GetCurrent());
170 Local<Context> local_env;
173 local_env = env.local();
176 // Local context should still be live.
177 CHECK(!local_env.IsEmpty());
180 v8::Handle<v8::Primitive> undef = v8::Undefined();
181 CHECK(!undef.IsEmpty());
182 CHECK(undef->IsUndefined());
184 const char* c_source = "1 + 2 + 3";
185 Local<String> source = String::New(c_source);
186 Local<Script> script = Script::Compile(source);
187 CHECK_EQ(6, script->Run()->Int32Value());
193 THREADED_TEST(IsolateOfContext) {
194 v8::HandleScope scope(v8::Isolate::GetCurrent());
195 v8::Handle<Context> env = Context::New(v8::Isolate::GetCurrent());
197 CHECK(!env->InContext());
198 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
200 CHECK(env->InContext());
201 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
203 CHECK(!env->InContext());
204 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent());
208 THREADED_TEST(ReceiverSignature) {
210 v8::HandleScope scope(env->GetIsolate());
211 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
212 v8::Handle<v8::Signature> sig = v8::Signature::New(fun);
213 fun->PrototypeTemplate()->Set(
215 v8::FunctionTemplate::New(IncrementingSignatureCallback,
218 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
219 signature_callback_count = 0;
223 CHECK_EQ(1, signature_callback_count);
224 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New();
225 sub_fun->Inherit(fun);
226 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction());
228 "var o = new SubFun();"
230 CHECK_EQ(2, signature_callback_count);
232 v8::TryCatch try_catch;
235 "o.m = Fun.prototype.m;"
237 CHECK_EQ(2, signature_callback_count);
238 CHECK(try_catch.HasCaught());
240 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New();
241 sub_fun->Inherit(fun);
242 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
244 "var o = new UnrelFun();"
245 "o.m = Fun.prototype.m;"
247 CHECK_EQ(2, signature_callback_count);
248 CHECK(try_catch.HasCaught());
252 THREADED_TEST(ArgumentSignature) {
254 v8::HandleScope scope(env->GetIsolate());
255 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New();
256 cons->SetClassName(v8_str("Cons"));
257 v8::Handle<v8::Signature> sig =
258 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons);
259 v8::Handle<v8::FunctionTemplate> fun =
260 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig);
261 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
262 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
264 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
265 CHECK(value1->IsTrue());
267 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
268 CHECK(value2->IsTrue());
270 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
271 CHECK(value3->IsTrue());
273 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New();
274 cons1->SetClassName(v8_str("Cons1"));
275 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New();
276 cons2->SetClassName(v8_str("Cons2"));
277 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New();
278 cons3->SetClassName(v8_str("Cons3"));
280 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
281 v8::Handle<v8::Signature> wsig =
282 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args);
283 v8::Handle<v8::FunctionTemplate> fun2 =
284 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig);
286 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
287 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
288 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
289 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
290 v8::Handle<Value> value4 = CompileRun(
291 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
292 "'[object Cons1],[object Cons2],[object Cons3]'");
293 CHECK(value4->IsTrue());
295 v8::Handle<Value> value5 = CompileRun(
296 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
297 CHECK(value5->IsTrue());
299 v8::Handle<Value> value6 = CompileRun(
300 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
301 CHECK(value6->IsTrue());
303 v8::Handle<Value> value7 = CompileRun(
304 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
305 "'[object Cons1],[object Cons2],[object Cons3],d';");
306 CHECK(value7->IsTrue());
308 v8::Handle<Value> value8 = CompileRun(
309 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
310 CHECK(value8->IsTrue());
314 THREADED_TEST(HulIgennem) {
316 v8::HandleScope scope(env->GetIsolate());
317 v8::Handle<v8::Primitive> undef = v8::Undefined();
318 Local<String> undef_str = undef->ToString();
319 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
320 undef_str->WriteUtf8(value);
321 CHECK_EQ(0, strcmp(value, "undefined"));
322 i::DeleteArray(value);
326 THREADED_TEST(Access) {
328 v8::HandleScope scope(env->GetIsolate());
329 Local<v8::Object> obj = v8::Object::New();
330 Local<Value> foo_before = obj->Get(v8_str("foo"));
331 CHECK(foo_before->IsUndefined());
332 Local<String> bar_str = v8_str("bar");
333 obj->Set(v8_str("foo"), bar_str);
334 Local<Value> foo_after = obj->Get(v8_str("foo"));
335 CHECK(!foo_after->IsUndefined());
336 CHECK(foo_after->IsString());
337 CHECK_EQ(bar_str, foo_after);
341 THREADED_TEST(AccessElement) {
343 v8::HandleScope scope(env->GetIsolate());
344 Local<v8::Object> obj = v8::Object::New();
345 Local<Value> before = obj->Get(1);
346 CHECK(before->IsUndefined());
347 Local<String> bar_str = v8_str("bar");
348 obj->Set(1, bar_str);
349 Local<Value> after = obj->Get(1);
350 CHECK(!after->IsUndefined());
351 CHECK(after->IsString());
352 CHECK_EQ(bar_str, after);
354 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
355 CHECK_EQ(v8_str("a"), value->Get(0));
356 CHECK_EQ(v8_str("b"), value->Get(1));
360 THREADED_TEST(Script) {
362 v8::HandleScope scope(env->GetIsolate());
363 const char* c_source = "1 + 2 + 3";
364 Local<String> source = String::New(c_source);
365 Local<Script> script = Script::Compile(source);
366 CHECK_EQ(6, script->Run()->Int32Value());
370 static uint16_t* AsciiToTwoByteString(const char* source) {
371 int array_length = i::StrLength(source) + 1;
372 uint16_t* converted = i::NewArray<uint16_t>(array_length);
373 for (int i = 0; i < array_length; i++) converted[i] = source[i];
378 class TestResource: public String::ExternalStringResource {
380 explicit TestResource(uint16_t* data, int* counter = NULL)
381 : data_(data), length_(0), counter_(counter) {
382 while (data[length_]) ++length_;
386 i::DeleteArray(data_);
387 if (counter_ != NULL) ++*counter_;
390 const uint16_t* data() const {
394 size_t length() const {
404 class TestAsciiResource: public String::ExternalAsciiStringResource {
406 explicit TestAsciiResource(const char* data, int* counter = NULL)
407 : data_(data), length_(strlen(data)), counter_(counter) { }
409 ~TestAsciiResource() {
410 i::DeleteArray(data_);
411 if (counter_ != NULL) ++*counter_;
414 const char* data() const {
418 size_t length() const {
428 THREADED_TEST(ScriptUsingStringResource) {
429 int dispose_count = 0;
430 const char* c_source = "1 + 2 * 3";
431 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
434 v8::HandleScope scope(env->GetIsolate());
435 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
436 Local<String> source = String::NewExternal(resource);
437 Local<Script> script = Script::Compile(source);
438 Local<Value> value = script->Run();
439 CHECK(value->IsNumber());
440 CHECK_EQ(7, value->Int32Value());
441 CHECK(source->IsExternal());
443 static_cast<TestResource*>(source->GetExternalStringResource()));
444 String::Encoding encoding = String::UNKNOWN_ENCODING;
445 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
446 source->GetExternalStringResourceBase(&encoding));
447 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
448 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
449 CHECK_EQ(0, dispose_count);
451 v8::internal::Isolate::Current()->compilation_cache()->Clear();
452 HEAP->CollectAllAvailableGarbage();
453 CHECK_EQ(1, dispose_count);
457 THREADED_TEST(ScriptUsingAsciiStringResource) {
458 int dispose_count = 0;
459 const char* c_source = "1 + 2 * 3";
462 v8::HandleScope scope(env->GetIsolate());
463 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source),
465 Local<String> source = String::NewExternal(resource);
466 CHECK(source->IsExternalAscii());
467 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
468 source->GetExternalAsciiStringResource());
469 String::Encoding encoding = String::UNKNOWN_ENCODING;
470 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
471 source->GetExternalStringResourceBase(&encoding));
472 CHECK_EQ(String::ASCII_ENCODING, encoding);
473 Local<Script> script = Script::Compile(source);
474 Local<Value> value = script->Run();
475 CHECK(value->IsNumber());
476 CHECK_EQ(7, value->Int32Value());
477 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
478 CHECK_EQ(0, dispose_count);
480 i::Isolate::Current()->compilation_cache()->Clear();
481 HEAP->CollectAllAvailableGarbage();
482 CHECK_EQ(1, dispose_count);
486 THREADED_TEST(ScriptMakingExternalString) {
487 int dispose_count = 0;
488 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
491 v8::HandleScope scope(env->GetIsolate());
492 Local<String> source = String::New(two_byte_source);
493 // Trigger GCs so that the newly allocated string moves to old gen.
494 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
495 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
496 CHECK_EQ(source->IsExternal(), false);
497 CHECK_EQ(source->IsExternalAscii(), false);
498 String::Encoding encoding = String::UNKNOWN_ENCODING;
499 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
500 CHECK_EQ(String::ASCII_ENCODING, encoding);
501 bool success = source->MakeExternal(new TestResource(two_byte_source,
504 Local<Script> script = Script::Compile(source);
505 Local<Value> value = script->Run();
506 CHECK(value->IsNumber());
507 CHECK_EQ(7, value->Int32Value());
508 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
509 CHECK_EQ(0, dispose_count);
511 i::Isolate::Current()->compilation_cache()->Clear();
512 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
513 CHECK_EQ(1, dispose_count);
517 THREADED_TEST(ScriptMakingExternalAsciiString) {
518 int dispose_count = 0;
519 const char* c_source = "1 + 2 * 3";
522 v8::HandleScope scope(env->GetIsolate());
523 Local<String> source = v8_str(c_source);
524 // Trigger GCs so that the newly allocated string moves to old gen.
525 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
526 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
527 bool success = source->MakeExternal(
528 new TestAsciiResource(i::StrDup(c_source), &dispose_count));
530 Local<Script> script = Script::Compile(source);
531 Local<Value> value = script->Run();
532 CHECK(value->IsNumber());
533 CHECK_EQ(7, value->Int32Value());
534 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
535 CHECK_EQ(0, dispose_count);
537 i::Isolate::Current()->compilation_cache()->Clear();
538 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
539 CHECK_EQ(1, dispose_count);
543 TEST(MakingExternalStringConditions) {
545 v8::HandleScope scope(env->GetIsolate());
547 // Free some space in the new space so that we can check freshness.
548 HEAP->CollectGarbage(i::NEW_SPACE);
549 HEAP->CollectGarbage(i::NEW_SPACE);
551 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
552 Local<String> small_string = String::New(two_byte_string);
553 i::DeleteArray(two_byte_string);
555 // We should refuse to externalize newly created small string.
556 CHECK(!small_string->CanMakeExternal());
557 // Trigger GCs so that the newly allocated string moves to old gen.
558 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
559 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
560 // Old space strings should be accepted.
561 CHECK(small_string->CanMakeExternal());
563 two_byte_string = AsciiToTwoByteString("small string 2");
564 small_string = String::New(two_byte_string);
565 i::DeleteArray(two_byte_string);
567 // We should refuse externalizing newly created small string.
568 CHECK(!small_string->CanMakeExternal());
569 for (int i = 0; i < 100; i++) {
570 String::Value value(small_string);
572 // Frequently used strings should be accepted.
573 CHECK(small_string->CanMakeExternal());
575 const int buf_size = 10 * 1024;
576 char* buf = i::NewArray<char>(buf_size);
577 memset(buf, 'a', buf_size);
578 buf[buf_size - 1] = '\0';
580 two_byte_string = AsciiToTwoByteString(buf);
581 Local<String> large_string = String::New(two_byte_string);
583 i::DeleteArray(two_byte_string);
584 // Large strings should be immediately accepted.
585 CHECK(large_string->CanMakeExternal());
589 TEST(MakingExternalAsciiStringConditions) {
591 v8::HandleScope scope(env->GetIsolate());
593 // Free some space in the new space so that we can check freshness.
594 HEAP->CollectGarbage(i::NEW_SPACE);
595 HEAP->CollectGarbage(i::NEW_SPACE);
597 Local<String> small_string = String::New("s1");
598 // We should refuse to externalize newly created small string.
599 CHECK(!small_string->CanMakeExternal());
600 // Trigger GCs so that the newly allocated string moves to old gen.
601 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
602 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
603 // Old space strings should be accepted.
604 CHECK(small_string->CanMakeExternal());
606 small_string = String::New("small string 2");
607 // We should refuse externalizing newly created small string.
608 CHECK(!small_string->CanMakeExternal());
609 for (int i = 0; i < 100; i++) {
610 String::Value value(small_string);
612 // Frequently used strings should be accepted.
613 CHECK(small_string->CanMakeExternal());
615 const int buf_size = 10 * 1024;
616 char* buf = i::NewArray<char>(buf_size);
617 memset(buf, 'a', buf_size);
618 buf[buf_size - 1] = '\0';
619 Local<String> large_string = String::New(buf);
621 // Large strings should be immediately accepted.
622 CHECK(large_string->CanMakeExternal());
626 TEST(MakingExternalUnalignedAsciiString) {
628 v8::HandleScope scope(env->GetIsolate());
630 CompileRun("function cons(a, b) { return a + b; }"
631 "function slice(a) { return a.substring(1); }");
632 // Create a cons string that will land in old pointer space.
633 Local<String> cons = Local<String>::Cast(CompileRun(
634 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
635 // Create a sliced string that will land in old pointer space.
636 Local<String> slice = Local<String>::Cast(CompileRun(
637 "slice('abcdefghijklmnopqrstuvwxyz');"));
639 // Trigger GCs so that the newly allocated string moves to old gen.
640 SimulateFullSpace(HEAP->old_pointer_space());
641 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
642 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
644 // Turn into external string with unaligned resource data.
645 int dispose_count = 0;
646 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
647 bool success = cons->MakeExternal(
648 new TestAsciiResource(i::StrDup(c_cons) + 1, &dispose_count));
650 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
651 success = slice->MakeExternal(
652 new TestAsciiResource(i::StrDup(c_slice) + 1, &dispose_count));
655 // Trigger GCs and force evacuation.
656 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
657 HEAP->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
661 THREADED_TEST(UsingExternalString) {
662 i::Factory* factory = i::Isolate::Current()->factory();
664 v8::HandleScope scope(v8::Isolate::GetCurrent());
665 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
666 Local<String> string =
667 String::NewExternal(new TestResource(two_byte_string));
668 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
669 // Trigger GCs so that the newly allocated string moves to old gen.
670 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
671 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
672 i::Handle<i::String> isymbol =
673 factory->InternalizedStringFromString(istring);
674 CHECK(isymbol->IsInternalizedString());
676 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
677 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
681 THREADED_TEST(UsingExternalAsciiString) {
682 i::Factory* factory = i::Isolate::Current()->factory();
684 v8::HandleScope scope(v8::Isolate::GetCurrent());
685 const char* one_byte_string = "test string";
686 Local<String> string = String::NewExternal(
687 new TestAsciiResource(i::StrDup(one_byte_string)));
688 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
689 // Trigger GCs so that the newly allocated string moves to old gen.
690 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now
691 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now
692 i::Handle<i::String> isymbol =
693 factory->InternalizedStringFromString(istring);
694 CHECK(isymbol->IsInternalizedString());
696 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
697 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
701 THREADED_TEST(ScavengeExternalString) {
702 i::FLAG_stress_compaction = false;
703 i::FLAG_gc_global = false;
704 int dispose_count = 0;
705 bool in_new_space = false;
707 v8::HandleScope scope(v8::Isolate::GetCurrent());
708 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
709 Local<String> string =
710 String::NewExternal(new TestResource(two_byte_string,
712 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
713 HEAP->CollectGarbage(i::NEW_SPACE);
714 in_new_space = HEAP->InNewSpace(*istring);
715 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
716 CHECK_EQ(0, dispose_count);
718 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
719 CHECK_EQ(1, dispose_count);
723 THREADED_TEST(ScavengeExternalAsciiString) {
724 i::FLAG_stress_compaction = false;
725 i::FLAG_gc_global = false;
726 int dispose_count = 0;
727 bool in_new_space = false;
729 v8::HandleScope scope(v8::Isolate::GetCurrent());
730 const char* one_byte_string = "test string";
731 Local<String> string = String::NewExternal(
732 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count));
733 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
734 HEAP->CollectGarbage(i::NEW_SPACE);
735 in_new_space = HEAP->InNewSpace(*istring);
736 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring));
737 CHECK_EQ(0, dispose_count);
739 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
740 CHECK_EQ(1, dispose_count);
744 class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
746 // Only used by non-threaded tests, so it can use static fields.
747 static int dispose_calls;
748 static int dispose_count;
750 TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
751 : TestAsciiResource(data, &dispose_count),
752 dispose_(dispose) { }
756 if (dispose_) delete this;
763 int TestAsciiResourceWithDisposeControl::dispose_count = 0;
764 int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
767 TEST(ExternalStringWithDisposeHandling) {
768 const char* c_source = "1 + 2 * 3";
770 // Use a stack allocated external string resource allocated object.
771 TestAsciiResourceWithDisposeControl::dispose_count = 0;
772 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
773 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
776 v8::HandleScope scope(env->GetIsolate());
777 Local<String> source = String::NewExternal(&res_stack);
778 Local<Script> script = Script::Compile(source);
779 Local<Value> value = script->Run();
780 CHECK(value->IsNumber());
781 CHECK_EQ(7, value->Int32Value());
782 HEAP->CollectAllAvailableGarbage();
783 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
785 i::Isolate::Current()->compilation_cache()->Clear();
786 HEAP->CollectAllAvailableGarbage();
787 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
788 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
790 // Use a heap allocated external string resource allocated object.
791 TestAsciiResourceWithDisposeControl::dispose_count = 0;
792 TestAsciiResourceWithDisposeControl::dispose_calls = 0;
793 TestAsciiResource* res_heap =
794 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
797 v8::HandleScope scope(env->GetIsolate());
798 Local<String> source = String::NewExternal(res_heap);
799 Local<Script> script = Script::Compile(source);
800 Local<Value> value = script->Run();
801 CHECK(value->IsNumber());
802 CHECK_EQ(7, value->Int32Value());
803 HEAP->CollectAllAvailableGarbage();
804 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count);
806 i::Isolate::Current()->compilation_cache()->Clear();
807 HEAP->CollectAllAvailableGarbage();
808 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
809 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count);
813 THREADED_TEST(StringConcat) {
816 v8::HandleScope scope(env->GetIsolate());
817 const char* one_byte_string_1 = "function a_times_t";
818 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
819 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
820 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
821 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
822 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
823 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
824 Local<String> left = v8_str(one_byte_string_1);
826 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
827 Local<String> right = String::New(two_byte_source);
828 i::DeleteArray(two_byte_source);
830 Local<String> source = String::Concat(left, right);
831 right = String::NewExternal(
832 new TestAsciiResource(i::StrDup(one_byte_extern_1)));
833 source = String::Concat(source, right);
834 right = String::NewExternal(
835 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
836 source = String::Concat(source, right);
837 right = v8_str(one_byte_string_2);
838 source = String::Concat(source, right);
840 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
841 right = String::New(two_byte_source);
842 i::DeleteArray(two_byte_source);
844 source = String::Concat(source, right);
845 right = String::NewExternal(
846 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
847 source = String::Concat(source, right);
848 Local<Script> script = Script::Compile(source);
849 Local<Value> value = script->Run();
850 CHECK(value->IsNumber());
851 CHECK_EQ(68, value->Int32Value());
853 i::Isolate::Current()->compilation_cache()->Clear();
854 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
855 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
859 THREADED_TEST(GlobalProperties) {
861 v8::HandleScope scope(env->GetIsolate());
862 v8::Handle<v8::Object> global = env->Global();
863 global->Set(v8_str("pi"), v8_num(3.1415926));
864 Local<Value> pi = global->Get(v8_str("pi"));
865 CHECK_EQ(3.1415926, pi->NumberValue());
870 static void CheckReturnValue(const T& t, i::Address callback) {
871 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
872 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
873 CHECK_EQ(v8::Isolate::GetCurrent(), t.GetIsolate());
874 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
875 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
877 bool is_runtime = (*o)->IsTheHole();
879 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
880 rv.Set(v8::Handle<v8::Object>());
881 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
882 CHECK_EQ(is_runtime, (*o)->IsTheHole());
884 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
885 // If CPU profiler is active check that when API callback is invoked
886 // VMState is set to EXTERNAL.
887 if (isolate->cpu_profiler()->is_profiling()) {
888 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
889 CHECK(isolate->external_callback_scope());
890 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
895 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
896 i::Address callback) {
897 ApiTestFuzzer::Fuzz();
898 CheckReturnValue(info, callback);
899 info.GetReturnValue().Set(v8_str("bad value"));
900 info.GetReturnValue().Set(v8_num(102));
904 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
905 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
909 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
910 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
913 static void construct_callback(
914 const v8::FunctionCallbackInfo<Value>& info) {
915 ApiTestFuzzer::Fuzz();
916 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
917 info.This()->Set(v8_str("x"), v8_num(1));
918 info.This()->Set(v8_str("y"), v8_num(2));
919 info.GetReturnValue().Set(v8_str("bad value"));
920 info.GetReturnValue().Set(info.This());
924 static void Return239Callback(
925 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
926 ApiTestFuzzer::Fuzz();
927 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
928 info.GetReturnValue().Set(v8_str("bad value"));
929 info.GetReturnValue().Set(v8_num(239));
933 template<typename Handler>
934 static void TestFunctionTemplateInitializer(Handler handler,
936 // Test constructor calls.
939 v8::HandleScope scope(env->GetIsolate());
941 Local<v8::FunctionTemplate> fun_templ =
942 v8::FunctionTemplate::New(handler);
943 Local<Function> fun = fun_templ->GetFunction();
944 env->Global()->Set(v8_str("obj"), fun);
945 Local<Script> script = v8_compile("obj()");
946 for (int i = 0; i < 30; i++) {
947 CHECK_EQ(102, script->Run()->Int32Value());
950 // Use SetCallHandler to initialize a function template, should work like
954 v8::HandleScope scope(env->GetIsolate());
956 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
957 fun_templ->SetCallHandler(handler_2);
958 Local<Function> fun = fun_templ->GetFunction();
959 env->Global()->Set(v8_str("obj"), fun);
960 Local<Script> script = v8_compile("obj()");
961 for (int i = 0; i < 30; i++) {
962 CHECK_EQ(102, script->Run()->Int32Value());
968 template<typename Constructor, typename Accessor>
969 static void TestFunctionTemplateAccessor(Constructor constructor,
972 v8::HandleScope scope(env->GetIsolate());
974 Local<v8::FunctionTemplate> fun_templ =
975 v8::FunctionTemplate::New(constructor);
976 fun_templ->SetClassName(v8_str("funky"));
977 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
978 Local<Function> fun = fun_templ->GetFunction();
979 env->Global()->Set(v8_str("obj"), fun);
980 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
981 CHECK_EQ(v8_str("[object funky]"), result);
982 CompileRun("var obj_instance = new obj();");
983 Local<Script> script;
984 script = v8_compile("obj_instance.x");
985 for (int i = 0; i < 30; i++) {
986 CHECK_EQ(1, script->Run()->Int32Value());
988 script = v8_compile("obj_instance.m");
989 for (int i = 0; i < 30; i++) {
990 CHECK_EQ(239, script->Run()->Int32Value());
995 THREADED_PROFILED_TEST(FunctionTemplate) {
996 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
997 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1001 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1002 ApiTestFuzzer::Fuzz();
1003 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1004 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1008 template<typename Callback>
1009 static void TestSimpleCallback(Callback callback) {
1011 v8::HandleScope scope(env->GetIsolate());
1013 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
1014 object_template->Set("callback", v8::FunctionTemplate::New(callback));
1015 v8::Local<v8::Object> object = object_template->NewInstance();
1016 (*env)->Global()->Set(v8_str("callback_object"), object);
1017 v8::Handle<v8::Script> script;
1018 script = v8_compile("callback_object.callback(17)");
1019 for (int i = 0; i < 30; i++) {
1020 CHECK_EQ(51424, script->Run()->Int32Value());
1022 script = v8_compile("callback_object.callback(17, 24)");
1023 for (int i = 0; i < 30; i++) {
1024 CHECK_EQ(51425, script->Run()->Int32Value());
1029 THREADED_PROFILED_TEST(SimpleCallback) {
1030 TestSimpleCallback(SimpleCallback);
1034 template<typename T>
1035 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1037 // constant return values
1038 static int32_t fast_return_value_int32 = 471;
1039 static uint32_t fast_return_value_uint32 = 571;
1040 static const double kFastReturnValueDouble = 2.7;
1041 // variable return values
1042 static bool fast_return_value_bool = false;
1043 enum ReturnValueOddball {
1045 kUndefinedReturnValue,
1046 kEmptyStringReturnValue
1048 static ReturnValueOddball fast_return_value_void;
1049 static bool fast_return_value_object_is_empty = false;
1051 // Helper function to avoid compiler error: insufficient contextual information
1052 // to determine type when applying FUNCTION_ADDR to a template function.
1053 static i::Address address_of(v8::FunctionCallback callback) {
1054 return FUNCTION_ADDR(callback);
1058 void FastReturnValueCallback<int32_t>(
1059 const v8::FunctionCallbackInfo<v8::Value>& info) {
1060 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1061 info.GetReturnValue().Set(fast_return_value_int32);
1065 void FastReturnValueCallback<uint32_t>(
1066 const v8::FunctionCallbackInfo<v8::Value>& info) {
1067 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1068 info.GetReturnValue().Set(fast_return_value_uint32);
1072 void FastReturnValueCallback<double>(
1073 const v8::FunctionCallbackInfo<v8::Value>& info) {
1074 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1075 info.GetReturnValue().Set(kFastReturnValueDouble);
1079 void FastReturnValueCallback<bool>(
1080 const v8::FunctionCallbackInfo<v8::Value>& info) {
1081 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1082 info.GetReturnValue().Set(fast_return_value_bool);
1086 void FastReturnValueCallback<void>(
1087 const v8::FunctionCallbackInfo<v8::Value>& info) {
1088 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1089 switch (fast_return_value_void) {
1090 case kNullReturnValue:
1091 info.GetReturnValue().SetNull();
1093 case kUndefinedReturnValue:
1094 info.GetReturnValue().SetUndefined();
1096 case kEmptyStringReturnValue:
1097 info.GetReturnValue().SetEmptyString();
1103 void FastReturnValueCallback<Object>(
1104 const v8::FunctionCallbackInfo<v8::Value>& info) {
1105 v8::Handle<v8::Object> object;
1106 if (!fast_return_value_object_is_empty) object = Object::New();
1107 info.GetReturnValue().Set(object);
1110 template<typename T>
1111 Handle<Value> TestFastReturnValues() {
1113 v8::HandleScope scope(env->GetIsolate());
1114 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
1115 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1116 object_template->Set("callback", v8::FunctionTemplate::New(callback));
1117 v8::Local<v8::Object> object = object_template->NewInstance();
1118 (*env)->Global()->Set(v8_str("callback_object"), object);
1119 return scope.Close(CompileRun("callback_object.callback()"));
1123 THREADED_PROFILED_TEST(FastReturnValues) {
1125 v8::HandleScope scope(v8::Isolate::GetCurrent());
1126 v8::Handle<v8::Value> value;
1127 // check int32_t and uint32_t
1128 int32_t int_values[] = {
1130 i::Smi::kMinValue, i::Smi::kMaxValue
1132 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) {
1133 for (int modifier = -1; modifier <= 1; modifier++) {
1134 int int_value = int_values[i] + modifier;
1136 fast_return_value_int32 = int_value;
1137 value = TestFastReturnValues<int32_t>();
1138 CHECK(value->IsInt32());
1139 CHECK(fast_return_value_int32 == value->Int32Value());
1141 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1142 value = TestFastReturnValues<uint32_t>();
1143 CHECK(value->IsUint32());
1144 CHECK(fast_return_value_uint32 == value->Uint32Value());
1148 value = TestFastReturnValues<double>();
1149 CHECK(value->IsNumber());
1150 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1151 // check bool values
1152 for (int i = 0; i < 2; i++) {
1153 fast_return_value_bool = i == 0;
1154 value = TestFastReturnValues<bool>();
1155 CHECK(value->IsBoolean());
1156 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1159 ReturnValueOddball oddballs[] = {
1161 kUndefinedReturnValue,
1162 kEmptyStringReturnValue
1164 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) {
1165 fast_return_value_void = oddballs[i];
1166 value = TestFastReturnValues<void>();
1167 switch (fast_return_value_void) {
1168 case kNullReturnValue:
1169 CHECK(value->IsNull());
1171 case kUndefinedReturnValue:
1172 CHECK(value->IsUndefined());
1174 case kEmptyStringReturnValue:
1175 CHECK(value->IsString());
1176 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1181 fast_return_value_object_is_empty = false;
1182 value = TestFastReturnValues<Object>();
1183 CHECK(value->IsObject());
1184 fast_return_value_object_is_empty = true;
1185 value = TestFastReturnValues<Object>();
1186 CHECK(value->IsUndefined());
1190 THREADED_TEST(FunctionTemplateSetLength) {
1192 v8::HandleScope scope(env->GetIsolate());
1194 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(
1195 handle_callback, Handle<v8::Value>(), Handle<v8::Signature>(), 23);
1196 Local<Function> fun = fun_templ->GetFunction();
1197 env->Global()->Set(v8_str("obj"), fun);
1198 Local<Script> script = v8_compile("obj.length");
1199 CHECK_EQ(23, script->Run()->Int32Value());
1202 Local<v8::FunctionTemplate> fun_templ =
1203 v8::FunctionTemplate::New(handle_callback);
1204 fun_templ->SetLength(22);
1205 Local<Function> fun = fun_templ->GetFunction();
1206 env->Global()->Set(v8_str("obj"), fun);
1207 Local<Script> script = v8_compile("obj.length");
1208 CHECK_EQ(22, script->Run()->Int32Value());
1211 // Without setting length it defaults to 0.
1212 Local<v8::FunctionTemplate> fun_templ =
1213 v8::FunctionTemplate::New(handle_callback);
1214 Local<Function> fun = fun_templ->GetFunction();
1215 env->Global()->Set(v8_str("obj"), fun);
1216 Local<Script> script = v8_compile("obj.length");
1217 CHECK_EQ(0, script->Run()->Int32Value());
1222 static void* expected_ptr;
1223 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1224 void* ptr = v8::External::Cast(*args.Data())->Value();
1225 CHECK_EQ(expected_ptr, ptr);
1226 args.GetReturnValue().Set(true);
1230 static void TestExternalPointerWrapping() {
1232 v8::HandleScope scope(env->GetIsolate());
1234 v8::Handle<v8::Value> data = v8::External::New(expected_ptr);
1236 v8::Handle<v8::Object> obj = v8::Object::New();
1237 obj->Set(v8_str("func"),
1238 v8::FunctionTemplate::New(callback, data)->GetFunction());
1239 env->Global()->Set(v8_str("obj"), obj);
1242 "function foo() {\n"
1243 " for (var i = 0; i < 13; i++) obj.func();\n"
1245 "foo(), true")->BooleanValue());
1249 THREADED_TEST(ExternalWrap) {
1250 // Check heap allocated object.
1253 TestExternalPointerWrapping();
1256 // Check stack allocated object.
1258 expected_ptr = &foo;
1259 TestExternalPointerWrapping();
1261 // Check not aligned addresses.
1263 char* s = new char[n];
1264 for (int i = 0; i < n; i++) {
1265 expected_ptr = s + i;
1266 TestExternalPointerWrapping();
1271 // Check several invalid addresses.
1272 expected_ptr = reinterpret_cast<void*>(1);
1273 TestExternalPointerWrapping();
1275 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1276 TestExternalPointerWrapping();
1278 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1279 TestExternalPointerWrapping();
1281 #if defined(V8_HOST_ARCH_X64)
1282 // Check a value with a leading 1 bit in x64 Smi encoding.
1283 expected_ptr = reinterpret_cast<void*>(0x400000000);
1284 TestExternalPointerWrapping();
1286 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1287 TestExternalPointerWrapping();
1289 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1290 TestExternalPointerWrapping();
1295 THREADED_TEST(FindInstanceInPrototypeChain) {
1297 v8::HandleScope scope(env->GetIsolate());
1299 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New();
1300 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New();
1301 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New();
1302 derived->Inherit(base);
1304 Local<v8::Function> base_function = base->GetFunction();
1305 Local<v8::Function> derived_function = derived->GetFunction();
1306 Local<v8::Function> other_function = other->GetFunction();
1308 Local<v8::Object> base_instance = base_function->NewInstance();
1309 Local<v8::Object> derived_instance = derived_function->NewInstance();
1310 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1311 Local<v8::Object> other_instance = other_function->NewInstance();
1312 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1313 other_instance->Set(v8_str("__proto__"), derived_instance2);
1315 // base_instance is only an instance of base.
1316 CHECK_EQ(base_instance,
1317 base_instance->FindInstanceInPrototypeChain(base));
1318 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1319 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1321 // derived_instance is an instance of base and derived.
1322 CHECK_EQ(derived_instance,
1323 derived_instance->FindInstanceInPrototypeChain(base));
1324 CHECK_EQ(derived_instance,
1325 derived_instance->FindInstanceInPrototypeChain(derived));
1326 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1328 // other_instance is an instance of other and its immediate
1329 // prototype derived_instance2 is an instance of base and derived.
1330 // Note, derived_instance is an instance of base and derived too,
1331 // but it comes after derived_instance2 in the prototype chain of
1333 CHECK_EQ(derived_instance2,
1334 other_instance->FindInstanceInPrototypeChain(base));
1335 CHECK_EQ(derived_instance2,
1336 other_instance->FindInstanceInPrototypeChain(derived));
1337 CHECK_EQ(other_instance,
1338 other_instance->FindInstanceInPrototypeChain(other));
1342 THREADED_TEST(TinyInteger) {
1344 v8::HandleScope scope(env->GetIsolate());
1345 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1347 int32_t value = 239;
1348 Local<v8::Integer> value_obj = v8::Integer::New(value);
1349 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1351 value_obj = v8::Integer::New(value, isolate);
1352 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1356 THREADED_TEST(BigSmiInteger) {
1358 v8::HandleScope scope(env->GetIsolate());
1359 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1361 int32_t value = i::Smi::kMaxValue;
1362 // We cannot add one to a Smi::kMaxValue without wrapping.
1363 if (i::kSmiValueSize < 32) {
1364 CHECK(i::Smi::IsValid(value));
1365 CHECK(!i::Smi::IsValid(value + 1));
1367 Local<v8::Integer> value_obj = v8::Integer::New(value);
1368 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1370 value_obj = v8::Integer::New(value, isolate);
1371 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1376 THREADED_TEST(BigInteger) {
1378 v8::HandleScope scope(env->GetIsolate());
1379 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1381 // We cannot add one to a Smi::kMaxValue without wrapping.
1382 if (i::kSmiValueSize < 32) {
1383 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1384 // The code will not be run in that case, due to the "if" guard.
1386 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1387 CHECK(value > i::Smi::kMaxValue);
1388 CHECK(!i::Smi::IsValid(value));
1390 Local<v8::Integer> value_obj = v8::Integer::New(value);
1391 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1393 value_obj = v8::Integer::New(value, isolate);
1394 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1399 THREADED_TEST(TinyUnsignedInteger) {
1401 v8::HandleScope scope(env->GetIsolate());
1402 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1404 uint32_t value = 239;
1406 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1407 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1409 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1410 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1414 THREADED_TEST(BigUnsignedSmiInteger) {
1416 v8::HandleScope scope(env->GetIsolate());
1417 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1419 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1420 CHECK(i::Smi::IsValid(value));
1421 CHECK(!i::Smi::IsValid(value + 1));
1423 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1424 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1426 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1427 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1431 THREADED_TEST(BigUnsignedInteger) {
1433 v8::HandleScope scope(env->GetIsolate());
1434 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1436 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1437 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1438 CHECK(!i::Smi::IsValid(value));
1440 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1441 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1443 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1444 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1448 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1450 v8::HandleScope scope(env->GetIsolate());
1451 v8::Isolate* isolate = v8::Isolate::GetCurrent();
1453 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1454 uint32_t value = INT32_MAX_AS_UINT + 1;
1455 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1457 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value);
1458 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1460 value_obj = v8::Integer::NewFromUnsigned(value, isolate);
1461 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1465 THREADED_TEST(IsNativeError) {
1467 v8::HandleScope scope(env->GetIsolate());
1468 v8::Handle<Value> syntax_error = CompileRun(
1469 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1470 CHECK(syntax_error->IsNativeError());
1471 v8::Handle<Value> not_error = CompileRun("{a:42}");
1472 CHECK(!not_error->IsNativeError());
1473 v8::Handle<Value> not_object = CompileRun("42");
1474 CHECK(!not_object->IsNativeError());
1478 THREADED_TEST(StringObject) {
1480 v8::HandleScope scope(env->GetIsolate());
1481 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1482 CHECK(boxed_string->IsStringObject());
1483 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1484 CHECK(!unboxed_string->IsStringObject());
1485 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1486 CHECK(!boxed_not_string->IsStringObject());
1487 v8::Handle<Value> not_object = CompileRun("0");
1488 CHECK(!not_object->IsStringObject());
1489 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1490 CHECK(!as_boxed.IsEmpty());
1491 Local<v8::String> the_string = as_boxed->ValueOf();
1492 CHECK(!the_string.IsEmpty());
1493 ExpectObject("\"test\"", the_string);
1494 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1495 CHECK(new_boxed_string->IsStringObject());
1496 as_boxed = new_boxed_string.As<v8::StringObject>();
1497 the_string = as_boxed->ValueOf();
1498 CHECK(!the_string.IsEmpty());
1499 ExpectObject("\"test\"", the_string);
1503 THREADED_TEST(NumberObject) {
1505 v8::HandleScope scope(env->GetIsolate());
1506 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1507 CHECK(boxed_number->IsNumberObject());
1508 v8::Handle<Value> unboxed_number = CompileRun("42");
1509 CHECK(!unboxed_number->IsNumberObject());
1510 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1511 CHECK(!boxed_not_number->IsNumberObject());
1512 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1513 CHECK(!as_boxed.IsEmpty());
1514 double the_number = as_boxed->ValueOf();
1515 CHECK_EQ(42.0, the_number);
1516 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43);
1517 CHECK(new_boxed_number->IsNumberObject());
1518 as_boxed = new_boxed_number.As<v8::NumberObject>();
1519 the_number = as_boxed->ValueOf();
1520 CHECK_EQ(43.0, the_number);
1524 THREADED_TEST(BooleanObject) {
1526 v8::HandleScope scope(env->GetIsolate());
1527 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1528 CHECK(boxed_boolean->IsBooleanObject());
1529 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1530 CHECK(!unboxed_boolean->IsBooleanObject());
1531 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1532 CHECK(!boxed_not_boolean->IsBooleanObject());
1533 v8::Handle<v8::BooleanObject> as_boxed =
1534 boxed_boolean.As<v8::BooleanObject>();
1535 CHECK(!as_boxed.IsEmpty());
1536 bool the_boolean = as_boxed->ValueOf();
1537 CHECK_EQ(true, the_boolean);
1538 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1539 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1540 CHECK(boxed_true->IsBooleanObject());
1541 CHECK(boxed_false->IsBooleanObject());
1542 as_boxed = boxed_true.As<v8::BooleanObject>();
1543 CHECK_EQ(true, as_boxed->ValueOf());
1544 as_boxed = boxed_false.As<v8::BooleanObject>();
1545 CHECK_EQ(false, as_boxed->ValueOf());
1549 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1551 v8::HandleScope scope(env->GetIsolate());
1553 Local<Value> primitive_false = Boolean::New(false);
1554 CHECK(primitive_false->IsBoolean());
1555 CHECK(!primitive_false->IsBooleanObject());
1556 CHECK(!primitive_false->BooleanValue());
1557 CHECK(!primitive_false->IsTrue());
1558 CHECK(primitive_false->IsFalse());
1560 Local<Value> false_value = BooleanObject::New(false);
1561 CHECK(!false_value->IsBoolean());
1562 CHECK(false_value->IsBooleanObject());
1563 CHECK(false_value->BooleanValue());
1564 CHECK(!false_value->IsTrue());
1565 CHECK(!false_value->IsFalse());
1567 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1568 CHECK(!false_boolean_object->IsBoolean());
1569 CHECK(false_boolean_object->IsBooleanObject());
1570 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1571 // CHECK(false_boolean_object->BooleanValue());
1572 CHECK(!false_boolean_object->ValueOf());
1573 CHECK(!false_boolean_object->IsTrue());
1574 CHECK(!false_boolean_object->IsFalse());
1576 Local<Value> primitive_true = Boolean::New(true);
1577 CHECK(primitive_true->IsBoolean());
1578 CHECK(!primitive_true->IsBooleanObject());
1579 CHECK(primitive_true->BooleanValue());
1580 CHECK(primitive_true->IsTrue());
1581 CHECK(!primitive_true->IsFalse());
1583 Local<Value> true_value = BooleanObject::New(true);
1584 CHECK(!true_value->IsBoolean());
1585 CHECK(true_value->IsBooleanObject());
1586 CHECK(true_value->BooleanValue());
1587 CHECK(!true_value->IsTrue());
1588 CHECK(!true_value->IsFalse());
1590 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1591 CHECK(!true_boolean_object->IsBoolean());
1592 CHECK(true_boolean_object->IsBooleanObject());
1593 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1594 // CHECK(true_boolean_object->BooleanValue());
1595 CHECK(true_boolean_object->ValueOf());
1596 CHECK(!true_boolean_object->IsTrue());
1597 CHECK(!true_boolean_object->IsFalse());
1601 THREADED_TEST(Number) {
1603 v8::HandleScope scope(env->GetIsolate());
1604 double PI = 3.1415926;
1605 Local<v8::Number> pi_obj = v8::Number::New(PI);
1606 CHECK_EQ(PI, pi_obj->NumberValue());
1610 THREADED_TEST(ToNumber) {
1612 v8::HandleScope scope(env->GetIsolate());
1613 Local<String> str = v8_str("3.1415926");
1614 CHECK_EQ(3.1415926, str->NumberValue());
1615 v8::Handle<v8::Boolean> t = v8::True();
1616 CHECK_EQ(1.0, t->NumberValue());
1617 v8::Handle<v8::Boolean> f = v8::False();
1618 CHECK_EQ(0.0, f->NumberValue());
1622 THREADED_TEST(Date) {
1624 v8::HandleScope scope(env->GetIsolate());
1625 double PI = 3.1415926;
1626 Local<Value> date = v8::Date::New(PI);
1627 CHECK_EQ(3.0, date->NumberValue());
1628 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42));
1629 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1633 THREADED_TEST(Boolean) {
1635 v8::HandleScope scope(env->GetIsolate());
1636 v8::Handle<v8::Boolean> t = v8::True();
1638 v8::Handle<v8::Boolean> f = v8::False();
1640 v8::Handle<v8::Primitive> u = v8::Undefined();
1641 CHECK(!u->BooleanValue());
1642 v8::Handle<v8::Primitive> n = v8::Null();
1643 CHECK(!n->BooleanValue());
1644 v8::Handle<String> str1 = v8_str("");
1645 CHECK(!str1->BooleanValue());
1646 v8::Handle<String> str2 = v8_str("x");
1647 CHECK(str2->BooleanValue());
1648 CHECK(!v8::Number::New(0)->BooleanValue());
1649 CHECK(v8::Number::New(-1)->BooleanValue());
1650 CHECK(v8::Number::New(1)->BooleanValue());
1651 CHECK(v8::Number::New(42)->BooleanValue());
1652 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1656 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1657 ApiTestFuzzer::Fuzz();
1658 args.GetReturnValue().Set(v8_num(13.4));
1662 static void GetM(Local<String> name,
1663 const v8::PropertyCallbackInfo<v8::Value>& info) {
1664 ApiTestFuzzer::Fuzz();
1665 info.GetReturnValue().Set(v8_num(876));
1669 THREADED_TEST(GlobalPrototype) {
1670 v8::HandleScope scope(v8::Isolate::GetCurrent());
1671 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
1672 func_templ->PrototypeTemplate()->Set(
1674 v8::FunctionTemplate::New(DummyCallHandler));
1675 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1676 templ->Set("x", v8_num(200));
1677 templ->SetAccessor(v8_str("m"), GetM);
1678 LocalContext env(0, templ);
1679 v8::Handle<Script> script(v8_compile("dummy()"));
1680 v8::Handle<Value> result(script->Run());
1681 CHECK_EQ(13.4, result->NumberValue());
1682 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1683 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1687 THREADED_TEST(ObjectTemplate) {
1688 v8::HandleScope scope(v8::Isolate::GetCurrent());
1689 Local<ObjectTemplate> templ1 = ObjectTemplate::New();
1690 templ1->Set("x", v8_num(10));
1691 templ1->Set("y", v8_num(13));
1693 Local<v8::Object> instance1 = templ1->NewInstance();
1694 env->Global()->Set(v8_str("p"), instance1);
1695 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1696 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1697 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New();
1698 fun->PrototypeTemplate()->Set("nirk", v8_num(123));
1699 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1700 templ2->Set("a", v8_num(12));
1701 templ2->Set("b", templ1);
1702 Local<v8::Object> instance2 = templ2->NewInstance();
1703 env->Global()->Set(v8_str("q"), instance2);
1704 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1705 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1706 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1707 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1711 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1712 ApiTestFuzzer::Fuzz();
1713 args.GetReturnValue().Set(v8_num(17.2));
1717 static void GetKnurd(Local<String> property,
1718 const v8::PropertyCallbackInfo<v8::Value>& info) {
1719 ApiTestFuzzer::Fuzz();
1720 info.GetReturnValue().Set(v8_num(15.2));
1724 THREADED_TEST(DescriptorInheritance) {
1725 v8::HandleScope scope(v8::Isolate::GetCurrent());
1726 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New();
1727 super->PrototypeTemplate()->Set("flabby",
1728 v8::FunctionTemplate::New(GetFlabby));
1729 super->PrototypeTemplate()->Set("PI", v8_num(3.14));
1731 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1733 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New();
1734 base1->Inherit(super);
1735 base1->PrototypeTemplate()->Set("v1", v8_num(20.1));
1737 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New();
1738 base2->Inherit(super);
1739 base2->PrototypeTemplate()->Set("v2", v8_num(10.1));
1743 env->Global()->Set(v8_str("s"), super->GetFunction());
1744 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1745 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1747 // Checks right __proto__ chain.
1748 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1749 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1751 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1753 // Instance accessor should not be visible on function object or its prototype
1754 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1755 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1756 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1758 env->Global()->Set(v8_str("obj"),
1759 base1->GetFunction()->NewInstance());
1760 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1761 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1762 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1763 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1764 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1766 env->Global()->Set(v8_str("obj2"),
1767 base2->GetFunction()->NewInstance());
1768 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1769 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1770 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1771 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1772 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1774 // base1 and base2 cannot cross reference to each's prototype
1775 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1776 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1780 int echo_named_call_count;
1783 static void EchoNamedProperty(Local<String> name,
1784 const v8::PropertyCallbackInfo<v8::Value>& info) {
1785 ApiTestFuzzer::Fuzz();
1786 CHECK_EQ(v8_str("data"), info.Data());
1787 echo_named_call_count++;
1788 info.GetReturnValue().Set(name);
1792 // Helper functions for Interceptor/Accessor interaction tests
1794 void SimpleAccessorGetter(Local<String> name,
1795 const v8::PropertyCallbackInfo<v8::Value>& info) {
1796 Handle<Object> self = info.This();
1797 info.GetReturnValue().Set(
1798 self->Get(String::Concat(v8_str("accessor_"), name)));
1801 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1802 const v8::PropertyCallbackInfo<void>& info) {
1803 Handle<Object> self = info.This();
1804 self->Set(String::Concat(v8_str("accessor_"), name), value);
1807 void EmptyInterceptorGetter(Local<String> name,
1808 const v8::PropertyCallbackInfo<v8::Value>& info) {
1811 void EmptyInterceptorSetter(Local<String> name,
1813 const v8::PropertyCallbackInfo<v8::Value>& info) {
1816 void InterceptorGetter(Local<String> name,
1817 const v8::PropertyCallbackInfo<v8::Value>& info) {
1818 // Intercept names that start with 'interceptor_'.
1819 String::Utf8Value utf8(name);
1820 char* name_str = *utf8;
1821 char prefix[] = "interceptor_";
1823 for (i = 0; name_str[i] && prefix[i]; ++i) {
1824 if (name_str[i] != prefix[i]) return;
1826 Handle<Object> self = info.This();
1827 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
1830 void InterceptorSetter(Local<String> name,
1832 const v8::PropertyCallbackInfo<v8::Value>& info) {
1833 // Intercept accesses that set certain integer values.
1834 if (value->IsInt32() && value->Int32Value() < 10000) {
1835 Handle<Object> self = info.This();
1836 self->SetHiddenValue(name, value);
1837 info.GetReturnValue().Set(value);
1841 void AddAccessor(Handle<FunctionTemplate> templ,
1842 Handle<String> name,
1843 v8::AccessorGetterCallback getter,
1844 v8::AccessorSetterCallback setter) {
1845 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
1848 void AddInterceptor(Handle<FunctionTemplate> templ,
1849 v8::NamedPropertyGetterCallback getter,
1850 v8::NamedPropertySetterCallback setter) {
1851 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
1855 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
1856 v8::HandleScope scope(v8::Isolate::GetCurrent());
1857 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1858 Handle<FunctionTemplate> child = FunctionTemplate::New();
1859 child->Inherit(parent);
1860 AddAccessor(parent, v8_str("age"),
1861 SimpleAccessorGetter, SimpleAccessorSetter);
1862 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1864 env->Global()->Set(v8_str("Child"), child->GetFunction());
1865 CompileRun("var child = new Child;"
1867 ExpectBoolean("child.hasOwnProperty('age')", false);
1868 ExpectInt32("child.age", 10);
1869 ExpectInt32("child.accessor_age", 10);
1873 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
1874 v8::HandleScope scope(v8::Isolate::GetCurrent());
1875 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1876 Handle<FunctionTemplate> child = FunctionTemplate::New();
1877 child->Inherit(parent);
1878 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1880 env->Global()->Set(v8_str("Child"), child->GetFunction());
1881 CompileRun("var child = new Child;"
1882 "var parent = child.__proto__;"
1883 "Object.defineProperty(parent, 'age', "
1884 " {get: function(){ return this.accessor_age; }, "
1885 " set: function(v){ this.accessor_age = v; }, "
1886 " enumerable: true, configurable: true});"
1888 ExpectBoolean("child.hasOwnProperty('age')", false);
1889 ExpectInt32("child.age", 10);
1890 ExpectInt32("child.accessor_age", 10);
1894 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
1895 v8::HandleScope scope(v8::Isolate::GetCurrent());
1896 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1897 Handle<FunctionTemplate> child = FunctionTemplate::New();
1898 child->Inherit(parent);
1899 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
1901 env->Global()->Set(v8_str("Child"), child->GetFunction());
1902 CompileRun("var child = new Child;"
1903 "var parent = child.__proto__;"
1904 "parent.name = 'Alice';");
1905 ExpectBoolean("child.hasOwnProperty('name')", false);
1906 ExpectString("child.name", "Alice");
1907 CompileRun("child.name = 'Bob';");
1908 ExpectString("child.name", "Bob");
1909 ExpectBoolean("child.hasOwnProperty('name')", true);
1910 ExpectString("parent.name", "Alice");
1914 THREADED_TEST(SwitchFromInterceptorToAccessor) {
1915 v8::HandleScope scope(v8::Isolate::GetCurrent());
1916 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1917 AddAccessor(templ, v8_str("age"),
1918 SimpleAccessorGetter, SimpleAccessorSetter);
1919 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1921 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1922 CompileRun("var obj = new Obj;"
1923 "function setAge(i){ obj.age = i; };"
1924 "for(var i = 0; i <= 10000; i++) setAge(i);");
1925 // All i < 10000 go to the interceptor.
1926 ExpectInt32("obj.interceptor_age", 9999);
1927 // The last i goes to the accessor.
1928 ExpectInt32("obj.accessor_age", 10000);
1932 THREADED_TEST(SwitchFromAccessorToInterceptor) {
1933 v8::HandleScope scope(v8::Isolate::GetCurrent());
1934 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1935 AddAccessor(templ, v8_str("age"),
1936 SimpleAccessorGetter, SimpleAccessorSetter);
1937 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1939 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1940 CompileRun("var obj = new Obj;"
1941 "function setAge(i){ obj.age = i; };"
1942 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1943 // All i >= 10000 go to the accessor.
1944 ExpectInt32("obj.accessor_age", 10000);
1945 // The last i goes to the interceptor.
1946 ExpectInt32("obj.interceptor_age", 9999);
1950 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
1951 v8::HandleScope scope(v8::Isolate::GetCurrent());
1952 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1953 Handle<FunctionTemplate> child = FunctionTemplate::New();
1954 child->Inherit(parent);
1955 AddAccessor(parent, v8_str("age"),
1956 SimpleAccessorGetter, SimpleAccessorSetter);
1957 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1959 env->Global()->Set(v8_str("Child"), child->GetFunction());
1960 CompileRun("var child = new Child;"
1961 "function setAge(i){ child.age = i; };"
1962 "for(var i = 0; i <= 10000; i++) setAge(i);");
1963 // All i < 10000 go to the interceptor.
1964 ExpectInt32("child.interceptor_age", 9999);
1965 // The last i goes to the accessor.
1966 ExpectInt32("child.accessor_age", 10000);
1970 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
1971 v8::HandleScope scope(v8::Isolate::GetCurrent());
1972 Handle<FunctionTemplate> parent = FunctionTemplate::New();
1973 Handle<FunctionTemplate> child = FunctionTemplate::New();
1974 child->Inherit(parent);
1975 AddAccessor(parent, v8_str("age"),
1976 SimpleAccessorGetter, SimpleAccessorSetter);
1977 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
1979 env->Global()->Set(v8_str("Child"), child->GetFunction());
1980 CompileRun("var child = new Child;"
1981 "function setAge(i){ child.age = i; };"
1982 "for(var i = 20000; i >= 9999; i--) setAge(i);");
1983 // All i >= 10000 go to the accessor.
1984 ExpectInt32("child.accessor_age", 10000);
1985 // The last i goes to the interceptor.
1986 ExpectInt32("child.interceptor_age", 9999);
1990 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
1991 v8::HandleScope scope(v8::Isolate::GetCurrent());
1992 Handle<FunctionTemplate> templ = FunctionTemplate::New();
1993 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
1995 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
1996 CompileRun("var obj = new Obj;"
1997 "function setter(i) { this.accessor_age = i; };"
1998 "function getter() { return this.accessor_age; };"
1999 "function setAge(i) { obj.age = i; };"
2000 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2001 "for(var i = 0; i <= 10000; i++) setAge(i);");
2002 // All i < 10000 go to the interceptor.
2003 ExpectInt32("obj.interceptor_age", 9999);
2004 // The last i goes to the JavaScript accessor.
2005 ExpectInt32("obj.accessor_age", 10000);
2006 // The installed JavaScript getter is still intact.
2007 // This last part is a regression test for issue 1651 and relies on the fact
2008 // that both interceptor and accessor are being installed on the same object.
2009 ExpectInt32("obj.age", 10000);
2010 ExpectBoolean("obj.hasOwnProperty('age')", true);
2011 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2015 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2016 v8::HandleScope scope(v8::Isolate::GetCurrent());
2017 Handle<FunctionTemplate> templ = FunctionTemplate::New();
2018 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2020 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2021 CompileRun("var obj = new Obj;"
2022 "function setter(i) { this.accessor_age = i; };"
2023 "function getter() { return this.accessor_age; };"
2024 "function setAge(i) { obj.age = i; };"
2025 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2026 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2027 // All i >= 10000 go to the accessor.
2028 ExpectInt32("obj.accessor_age", 10000);
2029 // The last i goes to the interceptor.
2030 ExpectInt32("obj.interceptor_age", 9999);
2031 // The installed JavaScript getter is still intact.
2032 // This last part is a regression test for issue 1651 and relies on the fact
2033 // that both interceptor and accessor are being installed on the same object.
2034 ExpectInt32("obj.age", 10000);
2035 ExpectBoolean("obj.hasOwnProperty('age')", true);
2036 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2040 THREADED_TEST(SwitchFromInterceptorToProperty) {
2041 v8::HandleScope scope(v8::Isolate::GetCurrent());
2042 Handle<FunctionTemplate> parent = FunctionTemplate::New();
2043 Handle<FunctionTemplate> child = FunctionTemplate::New();
2044 child->Inherit(parent);
2045 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2047 env->Global()->Set(v8_str("Child"), child->GetFunction());
2048 CompileRun("var child = new Child;"
2049 "function setAge(i){ child.age = i; };"
2050 "for(var i = 0; i <= 10000; i++) setAge(i);");
2051 // All i < 10000 go to the interceptor.
2052 ExpectInt32("child.interceptor_age", 9999);
2053 // The last i goes to child's own property.
2054 ExpectInt32("child.age", 10000);
2058 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2059 v8::HandleScope scope(v8::Isolate::GetCurrent());
2060 Handle<FunctionTemplate> parent = FunctionTemplate::New();
2061 Handle<FunctionTemplate> child = FunctionTemplate::New();
2062 child->Inherit(parent);
2063 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2065 env->Global()->Set(v8_str("Child"), child->GetFunction());
2066 CompileRun("var child = new Child;"
2067 "function setAge(i){ child.age = i; };"
2068 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2069 // All i >= 10000 go to child's own property.
2070 ExpectInt32("child.age", 10000);
2071 // The last i goes to the interceptor.
2072 ExpectInt32("child.interceptor_age", 9999);
2076 THREADED_TEST(NamedPropertyHandlerGetter) {
2077 echo_named_call_count = 0;
2078 v8::HandleScope scope(v8::Isolate::GetCurrent());
2079 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2080 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2084 env->Global()->Set(v8_str("obj"),
2085 templ->GetFunction()->NewInstance());
2086 CHECK_EQ(echo_named_call_count, 0);
2087 v8_compile("obj.x")->Run();
2088 CHECK_EQ(echo_named_call_count, 1);
2089 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2090 v8::Handle<Value> str = CompileRun(code);
2091 String::Utf8Value value(str);
2092 CHECK_EQ(*value, "oddlepoddle");
2093 // Check default behavior
2094 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2095 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2096 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2100 int echo_indexed_call_count = 0;
2103 static void EchoIndexedProperty(
2105 const v8::PropertyCallbackInfo<v8::Value>& info) {
2106 ApiTestFuzzer::Fuzz();
2107 CHECK_EQ(v8_num(637), info.Data());
2108 echo_indexed_call_count++;
2109 info.GetReturnValue().Set(v8_num(index));
2113 THREADED_TEST(IndexedPropertyHandlerGetter) {
2114 v8::HandleScope scope(v8::Isolate::GetCurrent());
2115 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2116 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2120 env->Global()->Set(v8_str("obj"),
2121 templ->GetFunction()->NewInstance());
2122 Local<Script> script = v8_compile("obj[900]");
2123 CHECK_EQ(script->Run()->Int32Value(), 900);
2127 v8::Handle<v8::Object> bottom;
2129 static void CheckThisIndexedPropertyHandler(
2131 const v8::PropertyCallbackInfo<v8::Value>& info) {
2132 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2133 ApiTestFuzzer::Fuzz();
2134 CHECK(info.This()->Equals(bottom));
2137 static void CheckThisNamedPropertyHandler(
2139 const v8::PropertyCallbackInfo<v8::Value>& info) {
2140 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2141 ApiTestFuzzer::Fuzz();
2142 CHECK(info.This()->Equals(bottom));
2145 void CheckThisIndexedPropertySetter(
2148 const v8::PropertyCallbackInfo<v8::Value>& info) {
2149 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2150 ApiTestFuzzer::Fuzz();
2151 CHECK(info.This()->Equals(bottom));
2155 void CheckThisNamedPropertySetter(
2156 Local<String> property,
2158 const v8::PropertyCallbackInfo<v8::Value>& info) {
2159 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2160 ApiTestFuzzer::Fuzz();
2161 CHECK(info.This()->Equals(bottom));
2164 void CheckThisIndexedPropertyQuery(
2166 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2167 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2168 ApiTestFuzzer::Fuzz();
2169 CHECK(info.This()->Equals(bottom));
2173 void CheckThisNamedPropertyQuery(
2174 Local<String> property,
2175 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2176 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2177 ApiTestFuzzer::Fuzz();
2178 CHECK(info.This()->Equals(bottom));
2182 void CheckThisIndexedPropertyDeleter(
2184 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2185 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2186 ApiTestFuzzer::Fuzz();
2187 CHECK(info.This()->Equals(bottom));
2191 void CheckThisNamedPropertyDeleter(
2192 Local<String> property,
2193 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2194 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2195 ApiTestFuzzer::Fuzz();
2196 CHECK(info.This()->Equals(bottom));
2200 void CheckThisIndexedPropertyEnumerator(
2201 const v8::PropertyCallbackInfo<v8::Array>& info) {
2202 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2203 ApiTestFuzzer::Fuzz();
2204 CHECK(info.This()->Equals(bottom));
2208 void CheckThisNamedPropertyEnumerator(
2209 const v8::PropertyCallbackInfo<v8::Array>& info) {
2210 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2211 ApiTestFuzzer::Fuzz();
2212 CHECK(info.This()->Equals(bottom));
2216 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2218 v8::HandleScope scope(env->GetIsolate());
2220 // Set up a prototype chain with three interceptors.
2221 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2222 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2223 CheckThisIndexedPropertyHandler,
2224 CheckThisIndexedPropertySetter,
2225 CheckThisIndexedPropertyQuery,
2226 CheckThisIndexedPropertyDeleter,
2227 CheckThisIndexedPropertyEnumerator);
2229 templ->InstanceTemplate()->SetNamedPropertyHandler(
2230 CheckThisNamedPropertyHandler,
2231 CheckThisNamedPropertySetter,
2232 CheckThisNamedPropertyQuery,
2233 CheckThisNamedPropertyDeleter,
2234 CheckThisNamedPropertyEnumerator);
2236 bottom = templ->GetFunction()->NewInstance();
2237 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2238 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2240 bottom->SetPrototype(middle);
2241 middle->SetPrototype(top);
2242 env->Global()->Set(v8_str("obj"), bottom);
2244 // Indexed and named get.
2245 Script::Compile(v8_str("obj[0]"))->Run();
2246 Script::Compile(v8_str("obj.x"))->Run();
2248 // Indexed and named set.
2249 Script::Compile(v8_str("obj[1] = 42"))->Run();
2250 Script::Compile(v8_str("obj.y = 42"))->Run();
2252 // Indexed and named query.
2253 Script::Compile(v8_str("0 in obj"))->Run();
2254 Script::Compile(v8_str("'x' in obj"))->Run();
2256 // Indexed and named deleter.
2257 Script::Compile(v8_str("delete obj[0]"))->Run();
2258 Script::Compile(v8_str("delete obj.x"))->Run();
2261 Script::Compile(v8_str("for (var p in obj) ;"))->Run();
2265 static void PrePropertyHandlerGet(
2267 const v8::PropertyCallbackInfo<v8::Value>& info) {
2268 ApiTestFuzzer::Fuzz();
2269 if (v8_str("pre")->Equals(key)) {
2270 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2275 static void PrePropertyHandlerQuery(
2277 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2278 if (v8_str("pre")->Equals(key)) {
2279 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2284 THREADED_TEST(PrePropertyHandler) {
2285 v8::HandleScope scope(v8::Isolate::GetCurrent());
2286 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
2287 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2289 PrePropertyHandlerQuery);
2290 LocalContext env(NULL, desc->InstanceTemplate());
2291 Script::Compile(v8_str(
2292 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
2293 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run();
2294 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2295 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run();
2296 CHECK_EQ(v8_str("Object: on"), result_on);
2297 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run();
2298 CHECK(result_post.IsEmpty());
2302 THREADED_TEST(UndefinedIsNotEnumerable) {
2304 v8::HandleScope scope(env->GetIsolate());
2305 v8::Handle<Value> result = Script::Compile(v8_str(
2306 "this.propertyIsEnumerable(undefined)"))->Run();
2307 CHECK(result->IsFalse());
2311 v8::Handle<Script> call_recursively_script;
2312 static const int kTargetRecursionDepth = 200; // near maximum
2315 static void CallScriptRecursivelyCall(
2316 const v8::FunctionCallbackInfo<v8::Value>& args) {
2317 ApiTestFuzzer::Fuzz();
2318 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2319 if (depth == kTargetRecursionDepth) return;
2320 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
2321 args.GetReturnValue().Set(call_recursively_script->Run());
2325 static void CallFunctionRecursivelyCall(
2326 const v8::FunctionCallbackInfo<v8::Value>& args) {
2327 ApiTestFuzzer::Fuzz();
2328 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2329 if (depth == kTargetRecursionDepth) {
2330 printf("[depth = %d]\n", depth);
2333 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1));
2334 v8::Handle<Value> function =
2335 args.This()->Get(v8_str("callFunctionRecursively"));
2336 args.GetReturnValue().Set(
2337 function.As<Function>()->Call(args.This(), 0, NULL));
2341 THREADED_TEST(DeepCrossLanguageRecursion) {
2342 v8::HandleScope scope(v8::Isolate::GetCurrent());
2343 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
2344 global->Set(v8_str("callScriptRecursively"),
2345 v8::FunctionTemplate::New(CallScriptRecursivelyCall));
2346 global->Set(v8_str("callFunctionRecursively"),
2347 v8::FunctionTemplate::New(CallFunctionRecursivelyCall));
2348 LocalContext env(NULL, global);
2350 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
2351 call_recursively_script = v8_compile("callScriptRecursively()");
2352 call_recursively_script->Run();
2353 call_recursively_script = v8::Handle<Script>();
2355 env->Global()->Set(v8_str("depth"), v8::Integer::New(0));
2356 Script::Compile(v8_str("callFunctionRecursively()"))->Run();
2360 static void ThrowingPropertyHandlerGet(
2362 const v8::PropertyCallbackInfo<v8::Value>& info) {
2363 ApiTestFuzzer::Fuzz();
2364 info.GetReturnValue().Set(v8::ThrowException(key));
2368 static void ThrowingPropertyHandlerSet(
2371 const v8::PropertyCallbackInfo<v8::Value>& info) {
2372 v8::ThrowException(key);
2373 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2377 THREADED_TEST(CallbackExceptionRegression) {
2378 v8::HandleScope scope(v8::Isolate::GetCurrent());
2379 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
2380 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2381 ThrowingPropertyHandlerSet);
2383 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2384 v8::Handle<Value> otto = Script::Compile(v8_str(
2385 "try { with (obj) { otto; } } catch (e) { e; }"))->Run();
2386 CHECK_EQ(v8_str("otto"), otto);
2387 v8::Handle<Value> netto = Script::Compile(v8_str(
2388 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run();
2389 CHECK_EQ(v8_str("netto"), netto);
2393 THREADED_TEST(FunctionPrototype) {
2394 v8::HandleScope scope(v8::Isolate::GetCurrent());
2395 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New();
2396 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2398 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2399 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak"));
2400 CHECK_EQ(script->Run()->Int32Value(), 321);
2404 THREADED_TEST(InternalFields) {
2406 v8::HandleScope scope(env->GetIsolate());
2408 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2409 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2410 instance_templ->SetInternalFieldCount(1);
2411 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2412 CHECK_EQ(1, obj->InternalFieldCount());
2413 CHECK(obj->GetInternalField(0)->IsUndefined());
2414 obj->SetInternalField(0, v8_num(17));
2415 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2419 THREADED_TEST(GlobalObjectInternalFields) {
2420 v8::HandleScope scope(v8::Isolate::GetCurrent());
2421 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
2422 global_template->SetInternalFieldCount(1);
2423 LocalContext env(NULL, global_template);
2424 v8::Handle<v8::Object> global_proxy = env->Global();
2425 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2426 CHECK_EQ(1, global->InternalFieldCount());
2427 CHECK(global->GetInternalField(0)->IsUndefined());
2428 global->SetInternalField(0, v8_num(17));
2429 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2433 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2435 v8::HandleScope scope(v8::Isolate::GetCurrent());
2437 v8::Local<v8::Object> global = env->Global();
2438 global->Set(0, v8::String::New("value"));
2439 CHECK(global->HasRealIndexedProperty(0));
2443 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2445 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2446 obj->SetAlignedPointerInInternalField(0, value);
2447 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2448 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2452 THREADED_TEST(InternalFieldsAlignedPointers) {
2454 v8::HandleScope scope(env->GetIsolate());
2456 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
2457 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2458 instance_templ->SetInternalFieldCount(1);
2459 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2460 CHECK_EQ(1, obj->InternalFieldCount());
2462 CheckAlignedPointerInInternalField(obj, NULL);
2464 int* heap_allocated = new int[100];
2465 CheckAlignedPointerInInternalField(obj, heap_allocated);
2466 delete[] heap_allocated;
2468 int stack_allocated[100];
2469 CheckAlignedPointerInInternalField(obj, stack_allocated);
2471 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2472 CheckAlignedPointerInInternalField(obj, huge);
2476 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2479 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2480 (*env)->SetAlignedPointerInEmbedderData(index, value);
2481 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2482 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2486 static void* AlignedTestPointer(int i) {
2487 return reinterpret_cast<void*>(i * 1234);
2491 THREADED_TEST(EmbedderDataAlignedPointers) {
2493 v8::HandleScope scope(env->GetIsolate());
2495 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2497 int* heap_allocated = new int[100];
2498 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2499 delete[] heap_allocated;
2501 int stack_allocated[100];
2502 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2504 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2505 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2507 // Test growing of the embedder data's backing store.
2508 for (int i = 0; i < 100; i++) {
2509 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2511 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2512 for (int i = 0; i < 100; i++) {
2513 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2518 static void CheckEmbedderData(LocalContext* env,
2520 v8::Handle<Value> data) {
2521 (*env)->SetEmbedderData(index, data);
2522 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2526 THREADED_TEST(EmbedderData) {
2528 v8::HandleScope scope(env->GetIsolate());
2530 CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps"));
2531 CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog."));
2532 CheckEmbedderData(&env, 1, v8::Number::New(1.2345));
2533 CheckEmbedderData(&env, 0, v8::Boolean::New(true));
2537 THREADED_TEST(IdentityHash) {
2539 v8::HandleScope scope(env->GetIsolate());
2541 // Ensure that the test starts with an fresh heap to test whether the hash
2542 // code is based on the address.
2543 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2544 Local<v8::Object> obj = v8::Object::New();
2545 int hash = obj->GetIdentityHash();
2546 int hash1 = obj->GetIdentityHash();
2547 CHECK_EQ(hash, hash1);
2548 int hash2 = v8::Object::New()->GetIdentityHash();
2549 // Since the identity hash is essentially a random number two consecutive
2550 // objects should not be assigned the same hash code. If the test below fails
2551 // the random number generator should be evaluated.
2552 CHECK_NE(hash, hash2);
2553 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2554 int hash3 = v8::Object::New()->GetIdentityHash();
2555 // Make sure that the identity hash is not based on the initial address of
2556 // the object alone. If the test below fails the random number generator
2557 // should be evaluated.
2558 CHECK_NE(hash, hash3);
2559 int hash4 = obj->GetIdentityHash();
2560 CHECK_EQ(hash, hash4);
2562 // Check identity hashes behaviour in the presence of JS accessors.
2563 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2565 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2566 Local<v8::Object> o1 = v8::Object::New();
2567 Local<v8::Object> o2 = v8::Object::New();
2568 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2572 "function cnst() { return 42; };\n"
2573 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2574 Local<v8::Object> o1 = v8::Object::New();
2575 Local<v8::Object> o2 = v8::Object::New();
2576 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2581 THREADED_TEST(SymbolProperties) {
2582 i::FLAG_harmony_symbols = true;
2585 v8::Isolate* isolate = env->GetIsolate();
2586 v8::HandleScope scope(isolate);
2588 v8::Local<v8::Object> obj = v8::Object::New();
2589 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2590 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol");
2592 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2594 // Check basic symbol functionality.
2595 CHECK(sym1->IsSymbol());
2596 CHECK(sym2->IsSymbol());
2597 CHECK(!obj->IsSymbol());
2599 CHECK(sym1->Equals(sym1));
2600 CHECK(sym2->Equals(sym2));
2601 CHECK(!sym1->Equals(sym2));
2602 CHECK(!sym2->Equals(sym1));
2603 CHECK(sym1->StrictEquals(sym1));
2604 CHECK(sym2->StrictEquals(sym2));
2605 CHECK(!sym1->StrictEquals(sym2));
2606 CHECK(!sym2->StrictEquals(sym1));
2608 CHECK(sym2->Name()->Equals(v8::String::New("my-symbol")));
2610 v8::Local<v8::Value> sym_val = sym2;
2611 CHECK(sym_val->IsSymbol());
2612 CHECK(sym_val->Equals(sym2));
2613 CHECK(sym_val->StrictEquals(sym2));
2614 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2616 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2617 CHECK(sym_obj->IsSymbolObject());
2618 CHECK(!sym2->IsSymbolObject());
2619 CHECK(!obj->IsSymbolObject());
2620 CHECK(sym_obj->Equals(sym2));
2621 CHECK(!sym_obj->StrictEquals(sym2));
2622 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2623 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2625 // Make sure delete of a non-existent symbol property works.
2626 CHECK(obj->Delete(sym1));
2627 CHECK(!obj->Has(sym1));
2629 CHECK(obj->Set(sym1, v8::Integer::New(1503)));
2630 CHECK(obj->Has(sym1));
2631 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2632 CHECK(obj->Set(sym1, v8::Integer::New(2002)));
2633 CHECK(obj->Has(sym1));
2634 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2635 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2637 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2638 int num_props = obj->GetPropertyNames()->Length();
2639 CHECK(obj->Set(v8::String::New("bla"), v8::Integer::New(20)));
2640 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2641 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2643 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2645 // Add another property and delete it afterwards to force the object in
2647 CHECK(obj->Set(sym2, v8::Integer::New(2008)));
2648 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2649 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2650 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2651 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2653 CHECK(obj->Has(sym1));
2654 CHECK(obj->Has(sym2));
2655 CHECK(obj->Delete(sym2));
2656 CHECK(obj->Has(sym1));
2657 CHECK(!obj->Has(sym2));
2658 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2659 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2663 class ScopedArrayBufferContents {
2665 explicit ScopedArrayBufferContents(
2666 const v8::ArrayBuffer::Contents& contents)
2667 : contents_(contents) {}
2668 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2669 void* Data() const { return contents_.Data(); }
2670 size_t ByteLength() const { return contents_.ByteLength(); }
2672 const v8::ArrayBuffer::Contents contents_;
2675 template <typename T>
2676 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2677 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2678 for (int i = 0; i < value->InternalFieldCount(); i++) {
2679 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2684 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2685 i::FLAG_harmony_array_buffer = true;
2686 i::FLAG_harmony_typed_arrays = true;
2689 v8::Isolate* isolate = env->GetIsolate();
2690 v8::HandleScope handle_scope(isolate);
2692 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(1024);
2693 CheckInternalFieldsAreZero(ab);
2694 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2695 CHECK(!ab->IsExternal());
2696 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2698 ScopedArrayBufferContents ab_contents(ab->Externalize());
2699 CHECK(ab->IsExternal());
2701 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2702 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2703 ASSERT(data != NULL);
2704 env->Global()->Set(v8_str("ab"), ab);
2706 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2707 CHECK_EQ(1024, result->Int32Value());
2709 result = CompileRun("var u8 = new Uint8Array(ab);"
2713 CHECK_EQ(1024, result->Int32Value());
2714 CHECK_EQ(0xFF, data[0]);
2715 CHECK_EQ(0xAA, data[1]);
2718 result = CompileRun("u8[0] + u8[1]");
2719 CHECK_EQ(0xDD, result->Int32Value());
2723 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2724 i::FLAG_harmony_array_buffer = true;
2725 i::FLAG_harmony_typed_arrays = true;
2728 v8::Isolate* isolate = env->GetIsolate();
2729 v8::HandleScope handle_scope(isolate);
2732 v8::Local<v8::Value> result =
2733 CompileRun("var ab1 = new ArrayBuffer(2);"
2734 "var u8_a = new Uint8Array(ab1);"
2736 "u8_a[1] = 0xFF; u8_a.buffer");
2737 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2738 CheckInternalFieldsAreZero(ab1);
2739 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2740 CHECK(!ab1->IsExternal());
2741 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2742 CHECK(ab1->IsExternal());
2744 result = CompileRun("ab1.byteLength");
2745 CHECK_EQ(2, result->Int32Value());
2746 result = CompileRun("u8_a[0]");
2747 CHECK_EQ(0xAA, result->Int32Value());
2748 result = CompileRun("u8_a[1]");
2749 CHECK_EQ(0xFF, result->Int32Value());
2750 result = CompileRun("var u8_b = new Uint8Array(ab1);"
2753 CHECK_EQ(0xBB, result->Int32Value());
2754 result = CompileRun("u8_b[1]");
2755 CHECK_EQ(0xFF, result->Int32Value());
2757 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2758 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2759 CHECK_EQ(0xBB, ab1_data[0]);
2760 CHECK_EQ(0xFF, ab1_data[1]);
2763 result = CompileRun("u8_a[0] + u8_a[1]");
2764 CHECK_EQ(0xDD, result->Int32Value());
2768 THREADED_TEST(ArrayBuffer_External) {
2769 i::FLAG_harmony_array_buffer = true;
2770 i::FLAG_harmony_typed_arrays = true;
2773 v8::Isolate* isolate = env->GetIsolate();
2774 v8::HandleScope handle_scope(isolate);
2776 i::ScopedVector<uint8_t> my_data(100);
2777 memset(my_data.start(), 0, 100);
2778 Local<v8::ArrayBuffer> ab3 = v8::ArrayBuffer::New(my_data.start(), 100);
2779 CheckInternalFieldsAreZero(ab3);
2780 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2781 CHECK(ab3->IsExternal());
2783 env->Global()->Set(v8_str("ab3"), ab3);
2785 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2786 CHECK_EQ(100, result->Int32Value());
2788 result = CompileRun("var u8_b = new Uint8Array(ab3);"
2792 CHECK_EQ(100, result->Int32Value());
2793 CHECK_EQ(0xBB, my_data[0]);
2794 CHECK_EQ(0xCC, my_data[1]);
2797 result = CompileRun("u8_b[0] + u8_b[1]");
2798 CHECK_EQ(0xDD, result->Int32Value());
2802 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
2803 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
2804 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
2808 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
2809 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
2810 CHECK_EQ(0, static_cast<int>(ta->Length()));
2811 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
2815 static void CheckIsTypedArrayVarNeutered(const char* name) {
2816 i::ScopedVector<char> source(1024);
2817 i::OS::SNPrintF(source,
2818 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
2820 CHECK(CompileRun(source.start())->IsTrue());
2821 v8::Handle<v8::TypedArray> ta =
2822 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
2823 CheckIsNeutered(ta);
2827 template <typename TypedArray, int kElementSize>
2828 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
2831 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
2832 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
2833 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
2834 CHECK_EQ(length, static_cast<int>(ta->Length()));
2835 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
2840 THREADED_TEST(ArrayBuffer_NeuteringApi) {
2842 v8::Isolate* isolate = env->GetIsolate();
2843 v8::HandleScope handle_scope(isolate);
2845 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(1024);
2847 v8::Handle<v8::Uint8Array> u8a =
2848 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
2849 v8::Handle<v8::Uint8ClampedArray> u8c =
2850 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
2851 v8::Handle<v8::Int8Array> i8a =
2852 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
2854 v8::Handle<v8::Uint16Array> u16a =
2855 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
2856 v8::Handle<v8::Int16Array> i16a =
2857 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
2859 v8::Handle<v8::Uint32Array> u32a =
2860 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
2861 v8::Handle<v8::Int32Array> i32a =
2862 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
2864 v8::Handle<v8::Float32Array> f32a =
2865 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
2866 v8::Handle<v8::Float64Array> f64a =
2867 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
2869 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
2870 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
2871 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
2872 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
2874 ScopedArrayBufferContents contents(buffer->Externalize());
2876 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
2877 CheckIsNeutered(u8a);
2878 CheckIsNeutered(u8c);
2879 CheckIsNeutered(i8a);
2880 CheckIsNeutered(u16a);
2881 CheckIsNeutered(i16a);
2882 CheckIsNeutered(u32a);
2883 CheckIsNeutered(i32a);
2884 CheckIsNeutered(f32a);
2885 CheckIsNeutered(f64a);
2886 CheckDataViewIsNeutered(dv);
2890 THREADED_TEST(ArrayBuffer_NeuteringScript) {
2892 v8::Isolate* isolate = env->GetIsolate();
2893 v8::HandleScope handle_scope(isolate);
2896 "var ab = new ArrayBuffer(1024);"
2897 "var u8a = new Uint8Array(ab, 1, 1023);"
2898 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
2899 "var i8a = new Int8Array(ab, 1, 1023);"
2900 "var u16a = new Uint16Array(ab, 2, 511);"
2901 "var i16a = new Int16Array(ab, 2, 511);"
2902 "var u32a = new Uint32Array(ab, 4, 255);"
2903 "var i32a = new Int32Array(ab, 4, 255);"
2904 "var f32a = new Float32Array(ab, 4, 255);"
2905 "var f64a = new Float64Array(ab, 8, 127);"
2906 "var dv = new DataView(ab, 1, 1023);");
2908 v8::Handle<v8::ArrayBuffer> ab =
2909 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
2911 v8::Handle<v8::DataView> dv =
2912 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
2914 ScopedArrayBufferContents contents(ab->Externalize());
2916 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
2917 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
2919 CheckIsTypedArrayVarNeutered("u8a");
2920 CheckIsTypedArrayVarNeutered("u8c");
2921 CheckIsTypedArrayVarNeutered("i8a");
2922 CheckIsTypedArrayVarNeutered("u16a");
2923 CheckIsTypedArrayVarNeutered("i16a");
2924 CheckIsTypedArrayVarNeutered("u32a");
2925 CheckIsTypedArrayVarNeutered("i32a");
2926 CheckIsTypedArrayVarNeutered("f32a");
2927 CheckIsTypedArrayVarNeutered("f64a");
2929 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
2930 CheckDataViewIsNeutered(dv);
2935 THREADED_TEST(HiddenProperties) {
2937 v8::HandleScope scope(env->GetIsolate());
2939 v8::Local<v8::Object> obj = v8::Object::New();
2940 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2941 v8::Local<v8::String> empty = v8_str("");
2942 v8::Local<v8::String> prop_name = v8_str("prop_name");
2944 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2946 // Make sure delete of a non-existent hidden value works
2947 CHECK(obj->DeleteHiddenValue(key));
2949 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503)));
2950 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2951 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2952 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2954 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2956 // Make sure we do not find the hidden property.
2957 CHECK(!obj->Has(empty));
2958 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2959 CHECK(obj->Get(empty)->IsUndefined());
2960 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2961 CHECK(obj->Set(empty, v8::Integer::New(2003)));
2962 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2963 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2965 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2967 // Add another property and delete it afterwards to force the object in
2969 CHECK(obj->Set(prop_name, v8::Integer::New(2008)));
2970 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2971 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2972 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2973 CHECK(obj->Delete(prop_name));
2974 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2976 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
2978 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2979 CHECK(obj->GetHiddenValue(key).IsEmpty());
2981 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002)));
2982 CHECK(obj->DeleteHiddenValue(key));
2983 CHECK(obj->GetHiddenValue(key).IsEmpty());
2987 THREADED_TEST(Regress97784) {
2988 // Regression test for crbug.com/97784
2989 // Messing with the Object.prototype should not have effect on
2990 // hidden properties.
2992 v8::HandleScope scope(env->GetIsolate());
2994 v8::Local<v8::Object> obj = v8::Object::New();
2995 v8::Local<v8::String> key = v8_str("hidden");
2998 "set_called = false;"
2999 "Object.defineProperty("
3000 " Object.prototype,"
3002 " {get: function() { return 45; },"
3003 " set: function() { set_called = true; }})");
3005 CHECK(obj->GetHiddenValue(key).IsEmpty());
3006 // Make sure that the getter and setter from Object.prototype is not invoked.
3007 // If it did we would have full access to the hidden properties in
3009 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42)));
3010 ExpectFalse("set_called");
3011 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3015 static bool interceptor_for_hidden_properties_called;
3016 static void InterceptorForHiddenProperties(
3017 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3018 interceptor_for_hidden_properties_called = true;
3022 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3023 LocalContext context;
3024 v8::HandleScope scope(context->GetIsolate());
3026 interceptor_for_hidden_properties_called = false;
3028 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3030 // Associate an interceptor with an object and start setting hidden values.
3031 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
3032 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3033 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3034 Local<v8::Function> function = fun_templ->GetFunction();
3035 Local<v8::Object> obj = function->NewInstance();
3036 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302)));
3037 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3038 CHECK(!interceptor_for_hidden_properties_called);
3042 THREADED_TEST(External) {
3043 v8::HandleScope scope(v8::Isolate::GetCurrent());
3045 Local<v8::External> ext = v8::External::New(&x);
3047 env->Global()->Set(v8_str("ext"), ext);
3048 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run();
3049 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3050 int* ptr = static_cast<int*>(reext->Value());
3055 // Make sure unaligned pointers are wrapped properly.
3056 char* data = i::StrDup("0123456789");
3057 Local<v8::Value> zero = v8::External::New(&data[0]);
3058 Local<v8::Value> one = v8::External::New(&data[1]);
3059 Local<v8::Value> two = v8::External::New(&data[2]);
3060 Local<v8::Value> three = v8::External::New(&data[3]);
3062 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3063 CHECK_EQ('0', *char_ptr);
3064 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3065 CHECK_EQ('1', *char_ptr);
3066 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3067 CHECK_EQ('2', *char_ptr);
3068 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3069 CHECK_EQ('3', *char_ptr);
3070 i::DeleteArray(data);
3074 THREADED_TEST(GlobalHandle) {
3075 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3076 v8::Persistent<String> global;
3078 v8::HandleScope scope(isolate);
3079 global.Reset(isolate, v8_str("str"));
3082 v8::HandleScope scope(isolate);
3083 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3088 v8::HandleScope scope(isolate);
3089 global.Reset(isolate, v8_str("str"));
3092 v8::HandleScope scope(isolate);
3093 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3099 THREADED_TEST(ResettingGlobalHandle) {
3100 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3101 v8::Persistent<String> global;
3103 v8::HandleScope scope(isolate);
3104 global.Reset(isolate, v8_str("str"));
3106 v8::internal::GlobalHandles* global_handles =
3107 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3108 int initial_handle_count = global_handles->global_handles_count();
3110 v8::HandleScope scope(isolate);
3111 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3114 v8::HandleScope scope(isolate);
3115 global.Reset(isolate, v8_str("longer"));
3117 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3119 v8::HandleScope scope(isolate);
3120 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3122 global.Dispose(isolate);
3123 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3127 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3128 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3129 v8::Persistent<String> global;
3131 v8::HandleScope scope(isolate);
3132 global.Reset(isolate, v8_str("str"));
3134 v8::internal::GlobalHandles* global_handles =
3135 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3136 int initial_handle_count = global_handles->global_handles_count();
3138 v8::HandleScope scope(isolate);
3139 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3142 v8::HandleScope scope(isolate);
3143 Local<String> empty;
3144 global.Reset(isolate, empty);
3146 CHECK(global.IsEmpty());
3147 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3151 THREADED_TEST(ClearAndLeakGlobal) {
3152 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3153 v8::internal::GlobalHandles* global_handles = NULL;
3154 int initial_handle_count = 0;
3155 v8::Persistent<String> global;
3157 v8::HandleScope scope(isolate);
3158 Local<String> str = v8_str("str");
3160 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3161 initial_handle_count = global_handles->global_handles_count();
3162 global.Reset(isolate, str);
3164 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1);
3165 String* str = global.ClearAndLeak();
3166 CHECK(global.IsEmpty());
3167 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1);
3168 global_handles->Destroy(reinterpret_cast<i::Object**>(str));
3169 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3173 THREADED_TEST(GlobalHandleUpcast) {
3174 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3175 v8::HandleScope scope(isolate);
3176 v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
3177 v8::Persistent<String> global_string(isolate, local);
3178 #ifdef V8_USE_UNSAFE_HANDLES
3179 v8::Persistent<Value> global_value =
3180 v8::Persistent<Value>::Cast(global_string);
3182 v8::Persistent<Value>& global_value =
3183 v8::Persistent<Value>::Cast(global_string);
3185 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3186 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3187 global_string.Dispose();
3191 THREADED_TEST(LocalHandle) {
3192 v8::HandleScope scope(v8::Isolate::GetCurrent());
3193 v8::Local<String> local = v8::Local<String>::New(v8_str("str"));
3194 CHECK_EQ(local->Length(), 3);
3196 local = v8::Local<String>::New(v8::Isolate::GetCurrent(), v8_str("str"));
3197 CHECK_EQ(local->Length(), 3);
3201 class WeakCallCounter {
3203 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3204 int id() { return id_; }
3205 void increment() { number_of_weak_calls_++; }
3206 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3209 int number_of_weak_calls_;
3213 static void WeakPointerCallback(v8::Isolate* isolate,
3214 Persistent<Value>* handle,
3215 WeakCallCounter* counter) {
3216 CHECK_EQ(1234, counter->id());
3217 counter->increment();
3218 handle->Dispose(isolate);
3222 static UniqueId MakeUniqueId(const Persistent<Value>& p) {
3223 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3227 THREADED_TEST(ApiObjectGroups) {
3229 v8::Isolate* iso = env->GetIsolate();
3230 HandleScope scope(iso);
3232 Persistent<Value> g1s1;
3233 Persistent<Value> g1s2;
3234 Persistent<Value> g1c1;
3235 Persistent<Value> g2s1;
3236 Persistent<Value> g2s2;
3237 Persistent<Value> g2c1;
3239 WeakCallCounter counter(1234);
3242 HandleScope scope(iso);
3243 g1s1.Reset(iso, Object::New());
3244 g1s2.Reset(iso, Object::New());
3245 g1c1.Reset(iso, Object::New());
3246 g1s1.MakeWeak(&counter, &WeakPointerCallback);
3247 g1s2.MakeWeak(&counter, &WeakPointerCallback);
3248 g1c1.MakeWeak(&counter, &WeakPointerCallback);
3250 g2s1.Reset(iso, Object::New());
3251 g2s2.Reset(iso, Object::New());
3252 g2c1.Reset(iso, Object::New());
3253 g2s1.MakeWeak(&counter, &WeakPointerCallback);
3254 g2s2.MakeWeak(&counter, &WeakPointerCallback);
3255 g2c1.MakeWeak(&counter, &WeakPointerCallback);
3258 Persistent<Value> root(iso, g1s1); // make a root.
3260 // Connect group 1 and 2, make a cycle.
3262 HandleScope scope(iso);
3263 CHECK(Local<Object>::New(iso, g1s2.As<Object>())->
3264 Set(0, Local<Value>::New(iso, g2s2)));
3265 CHECK(Local<Object>::New(iso, g2s1.As<Object>())->
3266 Set(0, Local<Value>::New(iso, g1s1)));
3270 UniqueId id1 = MakeUniqueId(g1s1);
3271 UniqueId id2 = MakeUniqueId(g2s2);
3272 iso->SetObjectGroupId(g1s1, id1);
3273 iso->SetObjectGroupId(g1s2, id1);
3274 iso->SetReferenceFromGroup(id1, g1c1);
3275 iso->SetObjectGroupId(g2s1, id2);
3276 iso->SetObjectGroupId(g2s2, id2);
3277 iso->SetReferenceFromGroup(id2, g2c1);
3279 // Do a single full GC, ensure incremental marking is stopped.
3280 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3282 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3284 // All object should be alive.
3285 CHECK_EQ(0, counter.NumberOfWeakCalls());
3288 root.MakeWeak(&counter, &WeakPointerCallback);
3289 // But make children strong roots---all the objects (except for children)
3290 // should be collectable now.
3291 g1c1.ClearWeak(iso);
3292 g2c1.ClearWeak(iso);
3294 // Groups are deleted, rebuild groups.
3296 UniqueId id1 = MakeUniqueId(g1s1);
3297 UniqueId id2 = MakeUniqueId(g2s2);
3298 iso->SetObjectGroupId(g1s1, id1);
3299 iso->SetObjectGroupId(g1s2, id1);
3300 iso->SetReferenceFromGroup(id1, g1c1);
3301 iso->SetObjectGroupId(g2s1, id2);
3302 iso->SetObjectGroupId(g2s2, id2);
3303 iso->SetReferenceFromGroup(id2, g2c1);
3306 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3308 // All objects should be gone. 5 global handles in total.
3309 CHECK_EQ(5, counter.NumberOfWeakCalls());
3311 // And now make children weak again and collect them.
3312 g1c1.MakeWeak(&counter, &WeakPointerCallback);
3313 g2c1.MakeWeak(&counter, &WeakPointerCallback);
3315 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3316 CHECK_EQ(7, counter.NumberOfWeakCalls());
3320 THREADED_TEST(ApiObjectGroupsCycle) {
3322 v8::Isolate* iso = env->GetIsolate();
3323 HandleScope scope(iso);
3325 WeakCallCounter counter(1234);
3327 Persistent<Value> g1s1;
3328 Persistent<Value> g1s2;
3329 Persistent<Value> g2s1;
3330 Persistent<Value> g2s2;
3331 Persistent<Value> g3s1;
3332 Persistent<Value> g3s2;
3333 Persistent<Value> g4s1;
3334 Persistent<Value> g4s2;
3337 HandleScope scope(iso);
3338 g1s1.Reset(iso, Object::New());
3339 g1s2.Reset(iso, Object::New());
3340 g1s1.MakeWeak(&counter, &WeakPointerCallback);
3341 g1s2.MakeWeak(&counter, &WeakPointerCallback);
3342 CHECK(g1s1.IsWeak(iso));
3343 CHECK(g1s2.IsWeak(iso));
3345 g2s1.Reset(iso, Object::New());
3346 g2s2.Reset(iso, Object::New());
3347 g2s1.MakeWeak(&counter, &WeakPointerCallback);
3348 g2s2.MakeWeak(&counter, &WeakPointerCallback);
3349 CHECK(g2s1.IsWeak(iso));
3350 CHECK(g2s2.IsWeak(iso));
3352 g3s1.Reset(iso, Object::New());
3353 g3s2.Reset(iso, Object::New());
3354 g3s1.MakeWeak(&counter, &WeakPointerCallback);
3355 g3s2.MakeWeak(&counter, &WeakPointerCallback);
3356 CHECK(g3s1.IsWeak(iso));
3357 CHECK(g3s2.IsWeak(iso));
3359 g4s1.Reset(iso, Object::New());
3360 g4s2.Reset(iso, Object::New());
3361 g4s1.MakeWeak(&counter, &WeakPointerCallback);
3362 g4s2.MakeWeak(&counter, &WeakPointerCallback);
3363 CHECK(g4s1.IsWeak(iso));
3364 CHECK(g4s2.IsWeak(iso));
3367 Persistent<Value> root(iso, g1s1); // make a root.
3369 // Connect groups. We're building the following cycle:
3370 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3373 UniqueId id1 = MakeUniqueId(g1s1);
3374 UniqueId id2 = MakeUniqueId(g2s1);
3375 UniqueId id3 = MakeUniqueId(g3s1);
3376 UniqueId id4 = MakeUniqueId(g4s1);
3377 iso->SetObjectGroupId(g1s1, id1);
3378 iso->SetObjectGroupId(g1s2, id1);
3379 iso->SetReferenceFromGroup(id1, g2s1);
3380 iso->SetObjectGroupId(g2s1, id2);
3381 iso->SetObjectGroupId(g2s2, id2);
3382 iso->SetReferenceFromGroup(id2, g3s1);
3383 iso->SetObjectGroupId(g3s1, id3);
3384 iso->SetObjectGroupId(g3s2, id3);
3385 iso->SetReferenceFromGroup(id3, g4s1);
3386 iso->SetObjectGroupId(g4s1, id4);
3387 iso->SetObjectGroupId(g4s2, id4);
3388 iso->SetReferenceFromGroup(id4, g1s1);
3390 // Do a single full GC
3391 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3393 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3395 // All object should be alive.
3396 CHECK_EQ(0, counter.NumberOfWeakCalls());
3399 root.MakeWeak(&counter, &WeakPointerCallback);
3401 // Groups are deleted, rebuild groups.
3403 UniqueId id1 = MakeUniqueId(g1s1);
3404 UniqueId id2 = MakeUniqueId(g2s1);
3405 UniqueId id3 = MakeUniqueId(g3s1);
3406 UniqueId id4 = MakeUniqueId(g4s1);
3407 iso->SetObjectGroupId(g1s1, id1);
3408 iso->SetObjectGroupId(g1s2, id1);
3409 iso->SetReferenceFromGroup(id1, g2s1);
3410 iso->SetObjectGroupId(g2s1, id2);
3411 iso->SetObjectGroupId(g2s2, id2);
3412 iso->SetReferenceFromGroup(id2, g3s1);
3413 iso->SetObjectGroupId(g3s1, id3);
3414 iso->SetObjectGroupId(g3s2, id3);
3415 iso->SetReferenceFromGroup(id3, g4s1);
3416 iso->SetObjectGroupId(g4s1, id4);
3417 iso->SetObjectGroupId(g4s2, id4);
3418 iso->SetReferenceFromGroup(id4, g1s1);
3421 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3423 // All objects should be gone. 9 global handles in total.
3424 CHECK_EQ(9, counter.NumberOfWeakCalls());
3428 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3429 // on the buildbots, so was made non-threaded for the time being.
3430 TEST(ApiObjectGroupsCycleForScavenger) {
3431 i::FLAG_stress_compaction = false;
3432 i::FLAG_gc_global = false;
3434 v8::Isolate* iso = env->GetIsolate();
3435 HandleScope scope(iso);
3437 WeakCallCounter counter(1234);
3439 Persistent<Value> g1s1;
3440 Persistent<Value> g1s2;
3441 Persistent<Value> g2s1;
3442 Persistent<Value> g2s2;
3443 Persistent<Value> g3s1;
3444 Persistent<Value> g3s2;
3447 HandleScope scope(iso);
3448 g1s1.Reset(iso, Object::New());
3449 g1s2.Reset(iso, Object::New());
3450 g1s1.MakeWeak(&counter, &WeakPointerCallback);
3451 g1s2.MakeWeak(&counter, &WeakPointerCallback);
3453 g2s1.Reset(iso, Object::New());
3454 g2s2.Reset(iso, Object::New());
3455 g2s1.MakeWeak(&counter, &WeakPointerCallback);
3456 g2s2.MakeWeak(&counter, &WeakPointerCallback);
3458 g3s1.Reset(iso, Object::New());
3459 g3s2.Reset(iso, Object::New());
3460 g3s1.MakeWeak(&counter, &WeakPointerCallback);
3461 g3s2.MakeWeak(&counter, &WeakPointerCallback);
3465 Persistent<Value> root(iso, g1s1);
3466 root.MarkPartiallyDependent(iso);
3468 // Connect groups. We're building the following cycle:
3469 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3472 HandleScope handle_scope(iso);
3473 g1s1.MarkPartiallyDependent(iso);
3474 g1s2.MarkPartiallyDependent(iso);
3475 g2s1.MarkPartiallyDependent(iso);
3476 g2s2.MarkPartiallyDependent(iso);
3477 g3s1.MarkPartiallyDependent(iso);
3478 g3s2.MarkPartiallyDependent(iso);
3479 iso->SetObjectGroupId(g1s1, UniqueId(1));
3480 iso->SetObjectGroupId(g1s2, UniqueId(1));
3481 Local<Object>::New(iso, g1s1.As<Object>())->Set(
3482 v8_str("x"), Local<Value>::New(iso, g2s1));
3483 iso->SetObjectGroupId(g2s1, UniqueId(2));
3484 iso->SetObjectGroupId(g2s2, UniqueId(2));
3485 Local<Object>::New(iso, g2s1.As<Object>())->Set(
3486 v8_str("x"), Local<Value>::New(iso, g3s1));
3487 iso->SetObjectGroupId(g3s1, UniqueId(3));
3488 iso->SetObjectGroupId(g3s2, UniqueId(3));
3489 Local<Object>::New(iso, g3s1.As<Object>())->Set(
3490 v8_str("x"), Local<Value>::New(iso, g1s1));
3493 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
3495 heap->CollectGarbage(i::NEW_SPACE);
3497 // All objects should be alive.
3498 CHECK_EQ(0, counter.NumberOfWeakCalls());
3501 root.MakeWeak(&counter, &WeakPointerCallback);
3502 root.MarkPartiallyDependent(iso);
3504 v8::Isolate* isolate = v8::Isolate::GetCurrent();
3505 // Groups are deleted, rebuild groups.
3507 HandleScope handle_scope(iso);
3508 g1s1.MarkPartiallyDependent(isolate);
3509 g1s2.MarkPartiallyDependent(isolate);
3510 g2s1.MarkPartiallyDependent(isolate);
3511 g2s2.MarkPartiallyDependent(isolate);
3512 g3s1.MarkPartiallyDependent(isolate);
3513 g3s2.MarkPartiallyDependent(isolate);
3514 iso->SetObjectGroupId(g1s1, UniqueId(1));
3515 iso->SetObjectGroupId(g1s2, UniqueId(1));
3516 Local<Object>::New(iso, g1s1.As<Object>())->Set(
3517 v8_str("x"), Local<Value>::New(iso, g2s1));
3518 iso->SetObjectGroupId(g2s1, UniqueId(2));
3519 iso->SetObjectGroupId(g2s2, UniqueId(2));
3520 Local<Object>::New(iso, g2s1.As<Object>())->Set(
3521 v8_str("x"), Local<Value>::New(iso, g3s1));
3522 iso->SetObjectGroupId(g3s1, UniqueId(3));
3523 iso->SetObjectGroupId(g3s2, UniqueId(3));
3524 Local<Object>::New(iso, g3s1.As<Object>())->Set(
3525 v8_str("x"), Local<Value>::New(iso, g1s1));
3528 heap->CollectGarbage(i::NEW_SPACE);
3530 // All objects should be gone. 7 global handles in total.
3531 CHECK_EQ(7, counter.NumberOfWeakCalls());
3535 THREADED_TEST(ScriptException) {
3537 v8::HandleScope scope(env->GetIsolate());
3538 Local<Script> script = Script::Compile(v8_str("throw 'panama!';"));
3539 v8::TryCatch try_catch;
3540 Local<Value> result = script->Run();
3541 CHECK(result.IsEmpty());
3542 CHECK(try_catch.HasCaught());
3543 String::Utf8Value exception_value(try_catch.Exception());
3544 CHECK_EQ(*exception_value, "panama!");
3548 TEST(TryCatchCustomException) {
3550 v8::HandleScope scope(env->GetIsolate());
3551 v8::TryCatch try_catch;
3552 CompileRun("function CustomError() { this.a = 'b'; }"
3553 "(function f() { throw new CustomError(); })();");
3554 CHECK(try_catch.HasCaught());
3555 CHECK(try_catch.Exception()->ToObject()->
3556 Get(v8_str("a"))->Equals(v8_str("b")));
3560 bool message_received;
3563 static void check_message_0(v8::Handle<v8::Message> message,
3564 v8::Handle<Value> data) {
3565 CHECK_EQ(5.76, data->NumberValue());
3566 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue());
3567 CHECK_EQ(7.56, message->GetScriptData()->NumberValue());
3568 message_received = true;
3572 THREADED_TEST(MessageHandler0) {
3573 message_received = false;
3574 v8::HandleScope scope(v8::Isolate::GetCurrent());
3575 CHECK(!message_received);
3576 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
3577 LocalContext context;
3578 v8::ScriptOrigin origin =
3579 v8::ScriptOrigin(v8_str("6.75"));
3580 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
3582 script->SetData(v8_str("7.56"));
3584 CHECK(message_received);
3585 // clear out the message listener
3586 v8::V8::RemoveMessageListeners(check_message_0);
3590 static void check_message_1(v8::Handle<v8::Message> message,
3591 v8::Handle<Value> data) {
3592 CHECK(data->IsNumber());
3593 CHECK_EQ(1337, data->Int32Value());
3594 message_received = true;
3598 TEST(MessageHandler1) {
3599 message_received = false;
3600 v8::HandleScope scope(v8::Isolate::GetCurrent());
3601 CHECK(!message_received);
3602 v8::V8::AddMessageListener(check_message_1);
3603 LocalContext context;
3604 CompileRun("throw 1337;");
3605 CHECK(message_received);
3606 // clear out the message listener
3607 v8::V8::RemoveMessageListeners(check_message_1);
3611 static void check_message_2(v8::Handle<v8::Message> message,
3612 v8::Handle<Value> data) {
3613 LocalContext context;
3614 CHECK(data->IsObject());
3615 v8::Local<v8::Value> hidden_property =
3616 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
3617 CHECK(v8_str("hidden value")->Equals(hidden_property));
3618 message_received = true;
3622 TEST(MessageHandler2) {
3623 message_received = false;
3624 v8::HandleScope scope(v8::Isolate::GetCurrent());
3625 CHECK(!message_received);
3626 v8::V8::AddMessageListener(check_message_2);
3627 LocalContext context;
3628 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
3629 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
3630 v8_str("hidden value"));
3631 context->Global()->Set(v8_str("error"), error);
3632 CompileRun("throw error;");
3633 CHECK(message_received);
3634 // clear out the message listener
3635 v8::V8::RemoveMessageListeners(check_message_2);
3639 THREADED_TEST(GetSetProperty) {
3640 LocalContext context;
3641 v8::HandleScope scope(context->GetIsolate());
3642 context->Global()->Set(v8_str("foo"), v8_num(14));
3643 context->Global()->Set(v8_str("12"), v8_num(92));
3644 context->Global()->Set(v8::Integer::New(16), v8_num(32));
3645 context->Global()->Set(v8_num(13), v8_num(56));
3646 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run();
3647 CHECK_EQ(14, foo->Int32Value());
3648 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run();
3649 CHECK_EQ(92, twelve->Int32Value());
3650 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run();
3651 CHECK_EQ(32, sixteen->Int32Value());
3652 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run();
3653 CHECK_EQ(56, thirteen->Int32Value());
3654 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value());
3655 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
3656 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
3657 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value());
3658 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
3659 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
3660 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value());
3661 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
3662 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
3666 THREADED_TEST(PropertyAttributes) {
3667 LocalContext context;
3668 v8::HandleScope scope(context->GetIsolate());
3670 Local<String> prop = v8_str("none");
3671 context->Global()->Set(prop, v8_num(7));
3672 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
3674 prop = v8_str("read_only");
3675 context->Global()->Set(prop, v8_num(7), v8::ReadOnly);
3676 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3677 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
3678 Script::Compile(v8_str("read_only = 9"))->Run();
3679 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3680 context->Global()->Set(prop, v8_num(10));
3681 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
3683 prop = v8_str("dont_delete");
3684 context->Global()->Set(prop, v8_num(13), v8::DontDelete);
3685 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
3686 Script::Compile(v8_str("delete dont_delete"))->Run();
3687 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
3688 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
3690 prop = v8_str("dont_enum");
3691 context->Global()->Set(prop, v8_num(28), v8::DontEnum);
3692 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
3694 prop = v8_str("absent");
3695 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
3696 Local<Value> fake_prop = v8_num(1);
3697 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
3700 Local<Value> exception =
3701 CompileRun("({ toString: function() { throw 'exception';} })");
3702 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
3703 CHECK(try_catch.HasCaught());
3704 String::Utf8Value exception_value(try_catch.Exception());
3705 CHECK_EQ("exception", *exception_value);
3710 THREADED_TEST(Array) {
3711 LocalContext context;
3712 v8::HandleScope scope(context->GetIsolate());
3713 Local<v8::Array> array = v8::Array::New();
3714 CHECK_EQ(0, array->Length());
3715 CHECK(array->Get(0)->IsUndefined());
3716 CHECK(!array->Has(0));
3717 CHECK(array->Get(100)->IsUndefined());
3718 CHECK(!array->Has(100));
3719 array->Set(2, v8_num(7));
3720 CHECK_EQ(3, array->Length());
3721 CHECK(!array->Has(0));
3722 CHECK(!array->Has(1));
3723 CHECK(array->Has(2));
3724 CHECK_EQ(7, array->Get(2)->Int32Value());
3725 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run();
3726 Local<v8::Array> arr = obj.As<v8::Array>();
3727 CHECK_EQ(3, arr->Length());
3728 CHECK_EQ(1, arr->Get(0)->Int32Value());
3729 CHECK_EQ(2, arr->Get(1)->Int32Value());
3730 CHECK_EQ(3, arr->Get(2)->Int32Value());
3731 array = v8::Array::New(27);
3732 CHECK_EQ(27, array->Length());
3733 array = v8::Array::New(-27);
3734 CHECK_EQ(0, array->Length());
3738 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
3739 v8::HandleScope scope(args.GetIsolate());
3740 ApiTestFuzzer::Fuzz();
3741 Local<v8::Array> result = v8::Array::New(args.Length());
3742 for (int i = 0; i < args.Length(); i++)
3743 result->Set(i, args[i]);
3744 args.GetReturnValue().Set(scope.Close(result));
3748 THREADED_TEST(Vector) {
3749 v8::HandleScope scope(v8::Isolate::GetCurrent());
3750 Local<ObjectTemplate> global = ObjectTemplate::New();
3751 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF));
3752 LocalContext context(0, global);
3754 const char* fun = "f()";
3755 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
3756 CHECK_EQ(0, a0->Length());
3758 const char* fun2 = "f(11)";
3759 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
3760 CHECK_EQ(1, a1->Length());
3761 CHECK_EQ(11, a1->Get(0)->Int32Value());
3763 const char* fun3 = "f(12, 13)";
3764 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
3765 CHECK_EQ(2, a2->Length());
3766 CHECK_EQ(12, a2->Get(0)->Int32Value());
3767 CHECK_EQ(13, a2->Get(1)->Int32Value());
3769 const char* fun4 = "f(14, 15, 16)";
3770 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
3771 CHECK_EQ(3, a3->Length());
3772 CHECK_EQ(14, a3->Get(0)->Int32Value());
3773 CHECK_EQ(15, a3->Get(1)->Int32Value());
3774 CHECK_EQ(16, a3->Get(2)->Int32Value());
3776 const char* fun5 = "f(17, 18, 19, 20)";
3777 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
3778 CHECK_EQ(4, a4->Length());
3779 CHECK_EQ(17, a4->Get(0)->Int32Value());
3780 CHECK_EQ(18, a4->Get(1)->Int32Value());
3781 CHECK_EQ(19, a4->Get(2)->Int32Value());
3782 CHECK_EQ(20, a4->Get(3)->Int32Value());
3786 THREADED_TEST(FunctionCall) {
3787 LocalContext context;
3788 v8::HandleScope scope(context->GetIsolate());
3792 " for (var i = 0; i < arguments.length; i++) {"
3793 " result.push(arguments[i]);"
3797 Local<Function> Foo =
3798 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
3800 v8::Handle<Value>* args0 = NULL;
3801 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
3802 CHECK_EQ(0, a0->Length());
3804 v8::Handle<Value> args1[] = { v8_num(1.1) };
3805 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
3806 CHECK_EQ(1, a1->Length());
3807 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
3809 v8::Handle<Value> args2[] = { v8_num(2.2),
3811 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
3812 CHECK_EQ(2, a2->Length());
3813 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
3814 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
3816 v8::Handle<Value> args3[] = { v8_num(4.4),
3819 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
3820 CHECK_EQ(3, a3->Length());
3821 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
3822 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
3823 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
3825 v8::Handle<Value> args4[] = { v8_num(7.7),
3829 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
3830 CHECK_EQ(4, a4->Length());
3831 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
3832 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
3833 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
3834 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
3838 static const char* js_code_causing_out_of_memory =
3839 "var a = new Array(); while(true) a.push(a);";
3842 // These tests run for a long time and prevent us from running tests
3843 // that come after them so they cannot run in parallel.
3845 // It's not possible to read a snapshot into a heap with different dimensions.
3846 if (i::Snapshot::IsEnabled()) return;
3848 static const int K = 1024;
3849 v8::ResourceConstraints constraints;
3850 constraints.set_max_young_space_size(256 * K);
3851 constraints.set_max_old_space_size(5 * K * K);
3852 v8::SetResourceConstraints(&constraints);
3854 // Execute a script that causes out of memory.
3855 LocalContext context;
3856 v8::HandleScope scope(context->GetIsolate());
3857 v8::V8::IgnoreOutOfMemoryException();
3858 Local<Script> script =
3859 Script::Compile(String::New(js_code_causing_out_of_memory));
3860 Local<Value> result = script->Run();
3862 // Check for out of memory state.
3863 CHECK(result.IsEmpty());
3864 CHECK(context->HasOutOfMemoryException());
3868 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) {
3869 ApiTestFuzzer::Fuzz();
3871 LocalContext context;
3872 v8::HandleScope scope(context->GetIsolate());
3873 Local<Script> script =
3874 Script::Compile(String::New(js_code_causing_out_of_memory));
3875 Local<Value> result = script->Run();
3877 // Check for out of memory state.
3878 CHECK(result.IsEmpty());
3879 CHECK(context->HasOutOfMemoryException());
3881 args.GetReturnValue().Set(result);
3885 TEST(OutOfMemoryNested) {
3886 // It's not possible to read a snapshot into a heap with different dimensions.
3887 if (i::Snapshot::IsEnabled()) return;
3889 static const int K = 1024;
3890 v8::ResourceConstraints constraints;
3891 constraints.set_max_young_space_size(256 * K);
3892 constraints.set_max_old_space_size(5 * K * K);
3893 v8::SetResourceConstraints(&constraints);
3895 v8::HandleScope scope(v8::Isolate::GetCurrent());
3896 Local<ObjectTemplate> templ = ObjectTemplate::New();
3897 templ->Set(v8_str("ProvokeOutOfMemory"),
3898 v8::FunctionTemplate::New(ProvokeOutOfMemory));
3899 LocalContext context(0, templ);
3900 v8::V8::IgnoreOutOfMemoryException();
3901 Local<Value> result = CompileRun(
3902 "var thrown = false;"
3904 " ProvokeOutOfMemory();"
3908 // Check for out of memory state.
3909 CHECK(result.IsEmpty());
3910 CHECK(context->HasOutOfMemoryException());
3914 TEST(HugeConsStringOutOfMemory) {
3915 // It's not possible to read a snapshot into a heap with different dimensions.
3916 if (i::Snapshot::IsEnabled()) return;
3918 static const int K = 1024;
3919 v8::ResourceConstraints constraints;
3920 constraints.set_max_young_space_size(256 * K);
3921 constraints.set_max_old_space_size(4 * K * K);
3922 v8::SetResourceConstraints(&constraints);
3924 // Execute a script that causes out of memory.
3925 v8::V8::IgnoreOutOfMemoryException();
3927 LocalContext context;
3928 v8::HandleScope scope(context->GetIsolate());
3930 // Build huge string. This should fail with out of memory exception.
3931 Local<Value> result = CompileRun(
3932 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();"
3933 "for (var i = 0; i < 22; i++) { str = str + str; }");
3935 // Check for out of memory state.
3936 CHECK(result.IsEmpty());
3937 CHECK(context->HasOutOfMemoryException());
3941 THREADED_TEST(ConstructCall) {
3942 LocalContext context;
3943 v8::HandleScope scope(context->GetIsolate());
3947 " for (var i = 0; i < arguments.length; i++) {"
3948 " result.push(arguments[i]);"
3952 Local<Function> Foo =
3953 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
3955 v8::Handle<Value>* args0 = NULL;
3956 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
3957 CHECK_EQ(0, a0->Length());
3959 v8::Handle<Value> args1[] = { v8_num(1.1) };
3960 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
3961 CHECK_EQ(1, a1->Length());
3962 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue());
3964 v8::Handle<Value> args2[] = { v8_num(2.2),
3966 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
3967 CHECK_EQ(2, a2->Length());
3968 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue());
3969 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue());
3971 v8::Handle<Value> args3[] = { v8_num(4.4),
3974 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
3975 CHECK_EQ(3, a3->Length());
3976 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue());
3977 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue());
3978 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue());
3980 v8::Handle<Value> args4[] = { v8_num(7.7),
3984 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
3985 CHECK_EQ(4, a4->Length());
3986 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue());
3987 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
3988 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
3989 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
3993 static void CheckUncle(v8::TryCatch* try_catch) {
3994 CHECK(try_catch->HasCaught());
3995 String::Utf8Value str_value(try_catch->Exception());
3996 CHECK_EQ(*str_value, "uncle?");
4001 THREADED_TEST(ConversionNumber) {
4003 v8::HandleScope scope(env->GetIsolate());
4004 // Very large number.
4005 CompileRun("var obj = Math.pow(2,32) * 1237;");
4006 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4007 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4008 CHECK_EQ(0, obj->ToInt32()->Value());
4009 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4011 CompileRun("var obj = -1234567890123;");
4012 obj = env->Global()->Get(v8_str("obj"));
4013 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4014 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4015 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4016 // Small positive integer.
4017 CompileRun("var obj = 42;");
4018 obj = env->Global()->Get(v8_str("obj"));
4019 CHECK_EQ(42.0, obj->ToNumber()->Value());
4020 CHECK_EQ(42, obj->ToInt32()->Value());
4021 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4022 // Negative integer.
4023 CompileRun("var obj = -37;");
4024 obj = env->Global()->Get(v8_str("obj"));
4025 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4026 CHECK_EQ(-37, obj->ToInt32()->Value());
4027 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4028 // Positive non-int32 integer.
4029 CompileRun("var obj = 0x81234567;");
4030 obj = env->Global()->Get(v8_str("obj"));
4031 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4032 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4033 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4035 CompileRun("var obj = 42.3;");
4036 obj = env->Global()->Get(v8_str("obj"));
4037 CHECK_EQ(42.3, obj->ToNumber()->Value());
4038 CHECK_EQ(42, obj->ToInt32()->Value());
4039 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4040 // Large negative fraction.
4041 CompileRun("var obj = -5726623061.75;");
4042 obj = env->Global()->Get(v8_str("obj"));
4043 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4044 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4045 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4049 THREADED_TEST(isNumberType) {
4051 v8::HandleScope scope(env->GetIsolate());
4052 // Very large number.
4053 CompileRun("var obj = Math.pow(2,32) * 1237;");
4054 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4055 CHECK(!obj->IsInt32());
4056 CHECK(!obj->IsUint32());
4057 // Large negative number.
4058 CompileRun("var obj = -1234567890123;");
4059 obj = env->Global()->Get(v8_str("obj"));
4060 CHECK(!obj->IsInt32());
4061 CHECK(!obj->IsUint32());
4062 // Small positive integer.
4063 CompileRun("var obj = 42;");
4064 obj = env->Global()->Get(v8_str("obj"));
4065 CHECK(obj->IsInt32());
4066 CHECK(obj->IsUint32());
4067 // Negative integer.
4068 CompileRun("var obj = -37;");
4069 obj = env->Global()->Get(v8_str("obj"));
4070 CHECK(obj->IsInt32());
4071 CHECK(!obj->IsUint32());
4072 // Positive non-int32 integer.
4073 CompileRun("var obj = 0x81234567;");
4074 obj = env->Global()->Get(v8_str("obj"));
4075 CHECK(!obj->IsInt32());
4076 CHECK(obj->IsUint32());
4078 CompileRun("var obj = 42.3;");
4079 obj = env->Global()->Get(v8_str("obj"));
4080 CHECK(!obj->IsInt32());
4081 CHECK(!obj->IsUint32());
4082 // Large negative fraction.
4083 CompileRun("var obj = -5726623061.75;");
4084 obj = env->Global()->Get(v8_str("obj"));
4085 CHECK(!obj->IsInt32());
4086 CHECK(!obj->IsUint32());
4088 CompileRun("var obj = 0.0;");
4089 obj = env->Global()->Get(v8_str("obj"));
4090 CHECK(obj->IsInt32());
4091 CHECK(obj->IsUint32());
4093 CompileRun("var obj = -0.0;");
4094 obj = env->Global()->Get(v8_str("obj"));
4095 CHECK(!obj->IsInt32());
4096 CHECK(!obj->IsUint32());
4100 THREADED_TEST(ConversionException) {
4102 v8::HandleScope scope(env->GetIsolate());
4104 "function TestClass() { };"
4105 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4106 "var obj = new TestClass();");
4107 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4109 v8::TryCatch try_catch;
4111 Local<Value> to_string_result = obj->ToString();
4112 CHECK(to_string_result.IsEmpty());
4113 CheckUncle(&try_catch);
4115 Local<Value> to_number_result = obj->ToNumber();
4116 CHECK(to_number_result.IsEmpty());
4117 CheckUncle(&try_catch);
4119 Local<Value> to_integer_result = obj->ToInteger();
4120 CHECK(to_integer_result.IsEmpty());
4121 CheckUncle(&try_catch);
4123 Local<Value> to_uint32_result = obj->ToUint32();
4124 CHECK(to_uint32_result.IsEmpty());
4125 CheckUncle(&try_catch);
4127 Local<Value> to_int32_result = obj->ToInt32();
4128 CHECK(to_int32_result.IsEmpty());
4129 CheckUncle(&try_catch);
4131 Local<Value> to_object_result = v8::Undefined()->ToObject();
4132 CHECK(to_object_result.IsEmpty());
4133 CHECK(try_catch.HasCaught());
4136 int32_t int32_value = obj->Int32Value();
4137 CHECK_EQ(0, int32_value);
4138 CheckUncle(&try_catch);
4140 uint32_t uint32_value = obj->Uint32Value();
4141 CHECK_EQ(0, uint32_value);
4142 CheckUncle(&try_catch);
4144 double number_value = obj->NumberValue();
4145 CHECK_NE(0, std::isnan(number_value));
4146 CheckUncle(&try_catch);
4148 int64_t integer_value = obj->IntegerValue();
4149 CHECK_EQ(0.0, static_cast<double>(integer_value));
4150 CheckUncle(&try_catch);
4154 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4155 ApiTestFuzzer::Fuzz();
4156 v8::ThrowException(v8_str("konto"));
4160 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4161 if (args.Length() < 1) {
4162 args.GetReturnValue().Set(false);
4165 v8::HandleScope scope(args.GetIsolate());
4166 v8::TryCatch try_catch;
4167 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run();
4168 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4169 args.GetReturnValue().Set(try_catch.HasCaught());
4173 THREADED_TEST(APICatch) {
4174 v8::HandleScope scope(v8::Isolate::GetCurrent());
4175 Local<ObjectTemplate> templ = ObjectTemplate::New();
4176 templ->Set(v8_str("ThrowFromC"),
4177 v8::FunctionTemplate::New(ThrowFromC));
4178 LocalContext context(0, templ);
4180 "var thrown = false;"
4186 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4187 CHECK(thrown->BooleanValue());
4191 THREADED_TEST(APIThrowTryCatch) {
4192 v8::HandleScope scope(v8::Isolate::GetCurrent());
4193 Local<ObjectTemplate> templ = ObjectTemplate::New();
4194 templ->Set(v8_str("ThrowFromC"),
4195 v8::FunctionTemplate::New(ThrowFromC));
4196 LocalContext context(0, templ);
4197 v8::TryCatch try_catch;
4198 CompileRun("ThrowFromC();");
4199 CHECK(try_catch.HasCaught());
4203 // Test that a try-finally block doesn't shadow a try-catch block
4204 // when setting up an external handler.
4206 // BUG(271): Some of the exception propagation does not work on the
4207 // ARM simulator because the simulator separates the C++ stack and the
4208 // JS stack. This test therefore fails on the simulator. The test is
4209 // not threaded to allow the threading tests to run on the simulator.
4210 TEST(TryCatchInTryFinally) {
4211 v8::HandleScope scope(v8::Isolate::GetCurrent());
4212 Local<ObjectTemplate> templ = ObjectTemplate::New();
4213 templ->Set(v8_str("CCatcher"),
4214 v8::FunctionTemplate::New(CCatcher));
4215 LocalContext context(0, templ);
4216 Local<Value> result = CompileRun("try {"
4218 " CCatcher('throw 7;');"
4223 CHECK(result->IsTrue());
4227 static void check_reference_error_message(
4228 v8::Handle<v8::Message> message,
4229 v8::Handle<v8::Value> data) {
4230 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4231 CHECK(message->Get()->Equals(v8_str(reference_error)));
4235 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4236 ApiTestFuzzer::Fuzz();
4241 // Test that overwritten methods are not invoked on uncaught exception
4242 // formatting. However, they are invoked when performing normal error
4243 // string conversions.
4244 TEST(APIThrowMessageOverwrittenToString) {
4245 v8::HandleScope scope(v8::Isolate::GetCurrent());
4246 v8::V8::AddMessageListener(check_reference_error_message);
4247 Local<ObjectTemplate> templ = ObjectTemplate::New();
4248 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail));
4249 LocalContext context(NULL, templ);
4250 CompileRun("asdf;");
4251 CompileRun("var limit = {};"
4252 "limit.valueOf = fail;"
4253 "Error.stackTraceLimit = limit;");
4255 CompileRun("Array.prototype.pop = fail;");
4256 CompileRun("Object.prototype.hasOwnProperty = fail;");
4257 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4258 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4259 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4260 CompileRun("ReferenceError.prototype.toString ="
4261 " function() { return 'Whoops' }");
4262 CompileRun("asdf;");
4263 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4264 CompileRun("asdf;");
4265 CompileRun("ReferenceError.prototype.constructor = void 0;");
4266 CompileRun("asdf;");
4267 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4268 CompileRun("asdf;");
4269 CompileRun("ReferenceError.prototype = new Object();");
4270 CompileRun("asdf;");
4271 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4272 CHECK(string->Equals(v8_str("Whoops")));
4273 CompileRun("ReferenceError.prototype.constructor = new Object();"
4274 "ReferenceError.prototype.constructor.name = 1;"
4275 "Number.prototype.toString = function() { return 'Whoops'; };"
4276 "ReferenceError.prototype.toString = Object.prototype.toString;");
4277 CompileRun("asdf;");
4278 v8::V8::RemoveMessageListeners(check_reference_error_message);
4282 static void check_custom_error_message(
4283 v8::Handle<v8::Message> message,
4284 v8::Handle<v8::Value> data) {
4285 const char* uncaught_error = "Uncaught MyError toString";
4286 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4290 TEST(CustomErrorToString) {
4291 LocalContext context;
4292 v8::HandleScope scope(context->GetIsolate());
4293 v8::V8::AddMessageListener(check_custom_error_message);
4295 "function MyError(name, message) { "
4296 " this.name = name; "
4297 " this.message = message; "
4299 "MyError.prototype = Object.create(Error.prototype); "
4300 "MyError.prototype.toString = function() { "
4301 " return 'MyError toString'; "
4303 "throw new MyError('my name', 'my message'); ");
4304 v8::V8::RemoveMessageListeners(check_custom_error_message);
4308 static void receive_message(v8::Handle<v8::Message> message,
4309 v8::Handle<v8::Value> data) {
4311 message_received = true;
4315 TEST(APIThrowMessage) {
4316 message_received = false;
4317 v8::HandleScope scope(v8::Isolate::GetCurrent());
4318 v8::V8::AddMessageListener(receive_message);
4319 Local<ObjectTemplate> templ = ObjectTemplate::New();
4320 templ->Set(v8_str("ThrowFromC"),
4321 v8::FunctionTemplate::New(ThrowFromC));
4322 LocalContext context(0, templ);
4323 CompileRun("ThrowFromC();");
4324 CHECK(message_received);
4325 v8::V8::RemoveMessageListeners(receive_message);
4329 TEST(APIThrowMessageAndVerboseTryCatch) {
4330 message_received = false;
4331 v8::HandleScope scope(v8::Isolate::GetCurrent());
4332 v8::V8::AddMessageListener(receive_message);
4333 Local<ObjectTemplate> templ = ObjectTemplate::New();
4334 templ->Set(v8_str("ThrowFromC"),
4335 v8::FunctionTemplate::New(ThrowFromC));
4336 LocalContext context(0, templ);
4337 v8::TryCatch try_catch;
4338 try_catch.SetVerbose(true);
4339 Local<Value> result = CompileRun("ThrowFromC();");
4340 CHECK(try_catch.HasCaught());
4341 CHECK(result.IsEmpty());
4342 CHECK(message_received);
4343 v8::V8::RemoveMessageListeners(receive_message);
4347 TEST(APIStackOverflowAndVerboseTryCatch) {
4348 message_received = false;
4349 LocalContext context;
4350 v8::HandleScope scope(context->GetIsolate());
4351 v8::V8::AddMessageListener(receive_message);
4352 v8::TryCatch try_catch;
4353 try_catch.SetVerbose(true);
4354 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
4355 CHECK(try_catch.HasCaught());
4356 CHECK(result.IsEmpty());
4357 CHECK(message_received);
4358 v8::V8::RemoveMessageListeners(receive_message);
4362 THREADED_TEST(ExternalScriptException) {
4363 v8::HandleScope scope(v8::Isolate::GetCurrent());
4364 Local<ObjectTemplate> templ = ObjectTemplate::New();
4365 templ->Set(v8_str("ThrowFromC"),
4366 v8::FunctionTemplate::New(ThrowFromC));
4367 LocalContext context(0, templ);
4369 v8::TryCatch try_catch;
4370 Local<Script> script
4371 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';"));
4372 Local<Value> result = script->Run();
4373 CHECK(result.IsEmpty());
4374 CHECK(try_catch.HasCaught());
4375 String::Utf8Value exception_value(try_catch.Exception());
4376 CHECK_EQ("konto", *exception_value);
4381 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
4382 ApiTestFuzzer::Fuzz();
4383 CHECK_EQ(4, args.Length());
4384 int count = args[0]->Int32Value();
4385 int cInterval = args[2]->Int32Value();
4387 v8::ThrowException(v8_str("FromC"));
4390 Local<v8::Object> global = Context::GetCurrent()->Global();
4391 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
4392 v8::Handle<Value> argv[] = { v8_num(count - 1),
4396 if (count % cInterval == 0) {
4397 v8::TryCatch try_catch;
4398 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
4399 int expected = args[3]->Int32Value();
4400 if (try_catch.HasCaught()) {
4401 CHECK_EQ(expected, count);
4402 CHECK(result.IsEmpty());
4403 CHECK(!i::Isolate::Current()->has_scheduled_exception());
4405 CHECK_NE(expected, count);
4407 args.GetReturnValue().Set(result);
4410 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
4417 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
4418 ApiTestFuzzer::Fuzz();
4419 CHECK_EQ(3, args.Length());
4420 bool equality = args[0]->BooleanValue();
4421 int count = args[1]->Int32Value();
4422 int expected = args[2]->Int32Value();
4424 CHECK_EQ(count, expected);
4426 CHECK_NE(count, expected);
4431 THREADED_TEST(EvalInTryFinally) {
4432 LocalContext context;
4433 v8::HandleScope scope(context->GetIsolate());
4434 v8::TryCatch try_catch;
4435 CompileRun("(function() {"
4437 " eval('asldkf (*&^&*^');"
4442 CHECK(!try_catch.HasCaught());
4446 // This test works by making a stack of alternating JavaScript and C
4447 // activations. These activations set up exception handlers with regular
4448 // intervals, one interval for C activations and another for JavaScript
4449 // activations. When enough activations have been created an exception is
4450 // thrown and we check that the right activation catches the exception and that
4451 // no other activations do. The right activation is always the topmost one with
4452 // a handler, regardless of whether it is in JavaScript or C.
4454 // The notation used to describe a test case looks like this:
4456 // *JS[4] *C[3] @JS[2] C[1] JS[0]
4458 // Each entry is an activation, either JS or C. The index is the count at that
4459 // level. Stars identify activations with exception handlers, the @ identifies
4460 // the exception handler that should catch the exception.
4462 // BUG(271): Some of the exception propagation does not work on the
4463 // ARM simulator because the simulator separates the C++ stack and the
4464 // JS stack. This test therefore fails on the simulator. The test is
4465 // not threaded to allow the threading tests to run on the simulator.
4466 TEST(ExceptionOrder) {
4467 v8::HandleScope scope(v8::Isolate::GetCurrent());
4468 Local<ObjectTemplate> templ = ObjectTemplate::New();
4469 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck));
4470 templ->Set(v8_str("CThrowCountDown"),
4471 v8::FunctionTemplate::New(CThrowCountDown));
4472 LocalContext context(0, templ);
4474 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
4475 " if (count == 0) throw 'FromJS';"
4476 " if (count % jsInterval == 0) {"
4478 " var value = CThrowCountDown(count - 1,"
4482 " check(false, count, expected);"
4485 " check(true, count, expected);"
4488 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
4491 Local<Function> fun =
4492 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
4495 // count jsInterval cInterval expected
4497 // *JS[4] *C[3] @JS[2] C[1] JS[0]
4498 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
4499 fun->Call(fun, argc, a0);
4501 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
4502 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
4503 fun->Call(fun, argc, a1);
4505 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
4506 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
4507 fun->Call(fun, argc, a2);
4509 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
4510 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
4511 fun->Call(fun, argc, a3);
4513 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
4514 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
4515 fun->Call(fun, argc, a4);
4517 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
4518 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
4519 fun->Call(fun, argc, a5);
4523 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
4524 ApiTestFuzzer::Fuzz();
4525 CHECK_EQ(1, args.Length());
4526 v8::ThrowException(args[0]);
4530 THREADED_TEST(ThrowValues) {
4531 v8::HandleScope scope(v8::Isolate::GetCurrent());
4532 Local<ObjectTemplate> templ = ObjectTemplate::New();
4533 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue));
4534 LocalContext context(0, templ);
4535 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4536 "function Run(obj) {"
4542 " return 'no exception';"
4544 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
4545 CHECK_EQ(5, result->Length());
4546 CHECK(result->Get(v8::Integer::New(0))->IsString());
4547 CHECK(result->Get(v8::Integer::New(1))->IsNumber());
4548 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value());
4549 CHECK(result->Get(v8::Integer::New(2))->IsNumber());
4550 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value());
4551 CHECK(result->Get(v8::Integer::New(3))->IsNull());
4552 CHECK(result->Get(v8::Integer::New(4))->IsUndefined());
4556 THREADED_TEST(CatchZero) {
4557 LocalContext context;
4558 v8::HandleScope scope(context->GetIsolate());
4559 v8::TryCatch try_catch;
4560 CHECK(!try_catch.HasCaught());
4561 Script::Compile(v8_str("throw 10"))->Run();
4562 CHECK(try_catch.HasCaught());
4563 CHECK_EQ(10, try_catch.Exception()->Int32Value());
4565 CHECK(!try_catch.HasCaught());
4566 Script::Compile(v8_str("throw 0"))->Run();
4567 CHECK(try_catch.HasCaught());
4568 CHECK_EQ(0, try_catch.Exception()->Int32Value());
4572 THREADED_TEST(CatchExceptionFromWith) {
4573 LocalContext context;
4574 v8::HandleScope scope(context->GetIsolate());
4575 v8::TryCatch try_catch;
4576 CHECK(!try_catch.HasCaught());
4577 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run();
4578 CHECK(try_catch.HasCaught());
4582 THREADED_TEST(TryCatchAndFinallyHidingException) {
4583 LocalContext context;
4584 v8::HandleScope scope(context->GetIsolate());
4585 v8::TryCatch try_catch;
4586 CHECK(!try_catch.HasCaught());
4587 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
4588 CompileRun("f({toString: function() { throw 42; }});");
4589 CHECK(!try_catch.HasCaught());
4593 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
4594 v8::TryCatch try_catch;
4598 THREADED_TEST(TryCatchAndFinally) {
4599 LocalContext context;
4600 v8::HandleScope scope(context->GetIsolate());
4601 context->Global()->Set(
4602 v8_str("native_with_try_catch"),
4603 v8::FunctionTemplate::New(WithTryCatch)->GetFunction());
4604 v8::TryCatch try_catch;
4605 CHECK(!try_catch.HasCaught());
4608 " throw new Error('a');\n"
4610 " native_with_try_catch();\n"
4612 CHECK(try_catch.HasCaught());
4616 static void TryCatchNestedHelper(int depth) {
4618 v8::TryCatch try_catch;
4619 try_catch.SetVerbose(true);
4620 TryCatchNestedHelper(depth - 1);
4621 CHECK(try_catch.HasCaught());
4622 try_catch.ReThrow();
4624 v8::ThrowException(v8_str("back"));
4629 TEST(TryCatchNested) {
4630 v8::V8::Initialize();
4631 LocalContext context;
4632 v8::HandleScope scope(context->GetIsolate());
4633 v8::TryCatch try_catch;
4634 TryCatchNestedHelper(5);
4635 CHECK(try_catch.HasCaught());
4636 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
4640 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
4641 CHECK(try_catch->HasCaught());
4642 Handle<Message> message = try_catch->Message();
4643 Handle<Value> resource = message->GetScriptResourceName();
4644 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
4645 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
4646 "Uncaught Error: a"));
4647 CHECK_EQ(1, message->GetLineNumber());
4648 CHECK_EQ(6, message->GetStartColumn());
4652 void TryCatchMixedNestingHelper(
4653 const v8::FunctionCallbackInfo<v8::Value>& args) {
4654 ApiTestFuzzer::Fuzz();
4655 v8::TryCatch try_catch;
4656 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
4657 CHECK(try_catch.HasCaught());
4658 TryCatchMixedNestingCheck(&try_catch);
4659 try_catch.ReThrow();
4663 // This test ensures that an outer TryCatch in the following situation:
4664 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
4665 // does not clobber the Message object generated for the inner TryCatch.
4666 // This exercises the ability of TryCatch.ReThrow() to restore the
4667 // inner pending Message before throwing the exception again.
4668 TEST(TryCatchMixedNesting) {
4669 v8::HandleScope scope(v8::Isolate::GetCurrent());
4670 v8::V8::Initialize();
4671 v8::TryCatch try_catch;
4672 Local<ObjectTemplate> templ = ObjectTemplate::New();
4673 templ->Set(v8_str("TryCatchMixedNestingHelper"),
4674 v8::FunctionTemplate::New(TryCatchMixedNestingHelper));
4675 LocalContext context(0, templ);
4676 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
4677 TryCatchMixedNestingCheck(&try_catch);
4681 THREADED_TEST(Equality) {
4682 LocalContext context;
4683 v8::Isolate* isolate = context->GetIsolate();
4684 v8::HandleScope scope(context->GetIsolate());
4685 // Check that equality works at all before relying on CHECK_EQ
4686 CHECK(v8_str("a")->Equals(v8_str("a")));
4687 CHECK(!v8_str("a")->Equals(v8_str("b")));
4689 CHECK_EQ(v8_str("a"), v8_str("a"));
4690 CHECK_NE(v8_str("a"), v8_str("b"));
4691 CHECK_EQ(v8_num(1), v8_num(1));
4692 CHECK_EQ(v8_num(1.00), v8_num(1));
4693 CHECK_NE(v8_num(1), v8_num(2));
4695 // Assume String is not internalized.
4696 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
4697 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
4698 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
4699 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
4700 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
4701 CHECK(v8_num(0)->StrictEquals(v8_num(-0)));
4702 Local<Value> not_a_number = v8_num(i::OS::nan_value());
4703 CHECK(!not_a_number->StrictEquals(not_a_number));
4704 CHECK(v8::False()->StrictEquals(v8::False()));
4705 CHECK(!v8::False()->StrictEquals(v8::Undefined()));
4707 v8::Handle<v8::Object> obj = v8::Object::New();
4708 v8::Persistent<v8::Object> alias(isolate, obj);
4709 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
4710 alias.Dispose(isolate);
4714 THREADED_TEST(MultiRun) {
4715 LocalContext context;
4716 v8::HandleScope scope(context->GetIsolate());
4717 Local<Script> script = Script::Compile(v8_str("x"));
4718 for (int i = 0; i < 10; i++)
4723 static void GetXValue(Local<String> name,
4724 const v8::PropertyCallbackInfo<v8::Value>& info) {
4725 ApiTestFuzzer::Fuzz();
4726 CHECK_EQ(info.Data(), v8_str("donut"));
4727 CHECK_EQ(name, v8_str("x"));
4728 info.GetReturnValue().Set(name);
4732 THREADED_TEST(SimplePropertyRead) {
4733 LocalContext context;
4734 v8::HandleScope scope(context->GetIsolate());
4735 Local<ObjectTemplate> templ = ObjectTemplate::New();
4736 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
4737 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4738 Local<Script> script = Script::Compile(v8_str("obj.x"));
4739 for (int i = 0; i < 10; i++) {
4740 Local<Value> result = script->Run();
4741 CHECK_EQ(result, v8_str("x"));
4746 THREADED_TEST(DefinePropertyOnAPIAccessor) {
4747 LocalContext context;
4748 v8::HandleScope scope(context->GetIsolate());
4749 Local<ObjectTemplate> templ = ObjectTemplate::New();
4750 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
4751 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4753 // Uses getOwnPropertyDescriptor to check the configurable status
4754 Local<Script> script_desc
4755 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( "
4757 "prop.configurable;"));
4758 Local<Value> result = script_desc->Run();
4759 CHECK_EQ(result->BooleanValue(), true);
4761 // Redefine get - but still configurable
4762 Local<Script> script_define
4763 = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
4764 " configurable: true };"
4765 "Object.defineProperty(obj, 'x', desc);"
4767 result = script_define->Run();
4768 CHECK_EQ(result, v8_num(42));
4770 // Check that the accessor is still configurable
4771 result = script_desc->Run();
4772 CHECK_EQ(result->BooleanValue(), true);
4774 // Redefine to a non-configurable
4776 = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
4777 " configurable: false };"
4778 "Object.defineProperty(obj, 'x', desc);"
4780 result = script_define->Run();
4781 CHECK_EQ(result, v8_num(43));
4782 result = script_desc->Run();
4783 CHECK_EQ(result->BooleanValue(), false);
4785 // Make sure that it is not possible to redefine again
4786 v8::TryCatch try_catch;
4787 result = script_define->Run();
4788 CHECK(try_catch.HasCaught());
4789 String::Utf8Value exception_value(try_catch.Exception());
4790 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
4794 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
4795 v8::HandleScope scope(v8::Isolate::GetCurrent());
4796 Local<ObjectTemplate> templ = ObjectTemplate::New();
4797 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
4798 LocalContext context;
4799 context->Global()->Set(v8_str("obj"), templ->NewInstance());
4801 Local<Script> script_desc = Script::Compile(v8_str("var prop ="
4802 "Object.getOwnPropertyDescriptor( "
4804 "prop.configurable;"));
4805 Local<Value> result = script_desc->Run();
4806 CHECK_EQ(result->BooleanValue(), true);
4808 Local<Script> script_define =
4809 Script::Compile(v8_str("var desc = {get: function(){return 42; },"
4810 " configurable: true };"
4811 "Object.defineProperty(obj, 'x', desc);"
4813 result = script_define->Run();
4814 CHECK_EQ(result, v8_num(42));
4817 result = script_desc->Run();
4818 CHECK_EQ(result->BooleanValue(), true);
4822 Script::Compile(v8_str("var desc = {get: function(){return 43; },"
4823 " configurable: false };"
4824 "Object.defineProperty(obj, 'x', desc);"
4826 result = script_define->Run();
4827 CHECK_EQ(result, v8_num(43));
4828 result = script_desc->Run();
4830 CHECK_EQ(result->BooleanValue(), false);
4832 v8::TryCatch try_catch;
4833 result = script_define->Run();
4834 CHECK(try_catch.HasCaught());
4835 String::Utf8Value exception_value(try_catch.Exception());
4836 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
4840 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
4842 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
4846 THREADED_TEST(DefineAPIAccessorOnObject) {
4847 v8::HandleScope scope(v8::Isolate::GetCurrent());
4848 Local<ObjectTemplate> templ = ObjectTemplate::New();
4849 LocalContext context;
4851 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4852 CompileRun("var obj2 = {};");
4854 CHECK(CompileRun("obj1.x")->IsUndefined());
4855 CHECK(CompileRun("obj2.x")->IsUndefined());
4857 CHECK(GetGlobalProperty(&context, "obj1")->
4858 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4860 ExpectString("obj1.x", "x");
4861 CHECK(CompileRun("obj2.x")->IsUndefined());
4863 CHECK(GetGlobalProperty(&context, "obj2")->
4864 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4866 ExpectString("obj1.x", "x");
4867 ExpectString("obj2.x", "x");
4869 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4870 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4872 CompileRun("Object.defineProperty(obj1, 'x',"
4873 "{ get: function() { return 'y'; }, configurable: true })");
4875 ExpectString("obj1.x", "y");
4876 ExpectString("obj2.x", "x");
4878 CompileRun("Object.defineProperty(obj2, 'x',"
4879 "{ get: function() { return 'y'; }, configurable: true })");
4881 ExpectString("obj1.x", "y");
4882 ExpectString("obj2.x", "y");
4884 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4885 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4887 CHECK(GetGlobalProperty(&context, "obj1")->
4888 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4889 CHECK(GetGlobalProperty(&context, "obj2")->
4890 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4892 ExpectString("obj1.x", "x");
4893 ExpectString("obj2.x", "x");
4895 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4896 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4898 // Define getters/setters, but now make them not configurable.
4899 CompileRun("Object.defineProperty(obj1, 'x',"
4900 "{ get: function() { return 'z'; }, configurable: false })");
4901 CompileRun("Object.defineProperty(obj2, 'x',"
4902 "{ get: function() { return 'z'; }, configurable: false })");
4904 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4905 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4907 ExpectString("obj1.x", "z");
4908 ExpectString("obj2.x", "z");
4910 CHECK(!GetGlobalProperty(&context, "obj1")->
4911 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4912 CHECK(!GetGlobalProperty(&context, "obj2")->
4913 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4915 ExpectString("obj1.x", "z");
4916 ExpectString("obj2.x", "z");
4920 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
4921 v8::HandleScope scope(v8::Isolate::GetCurrent());
4922 Local<ObjectTemplate> templ = ObjectTemplate::New();
4923 LocalContext context;
4925 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4926 CompileRun("var obj2 = {};");
4928 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
4931 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
4932 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
4935 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
4937 ExpectString("obj1.x", "x");
4938 ExpectString("obj2.x", "x");
4940 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
4941 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
4943 CHECK(!GetGlobalProperty(&context, "obj1")->
4944 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4945 CHECK(!GetGlobalProperty(&context, "obj2")->
4946 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
4949 v8::TryCatch try_catch;
4950 CompileRun("Object.defineProperty(obj1, 'x',"
4951 "{get: function() { return 'func'; }})");
4952 CHECK(try_catch.HasCaught());
4953 String::Utf8Value exception_value(try_catch.Exception());
4954 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
4957 v8::TryCatch try_catch;
4958 CompileRun("Object.defineProperty(obj2, 'x',"
4959 "{get: function() { return 'func'; }})");
4960 CHECK(try_catch.HasCaught());
4961 String::Utf8Value exception_value(try_catch.Exception());
4962 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
4967 static void Get239Value(Local<String> name,
4968 const v8::PropertyCallbackInfo<v8::Value>& info) {
4969 ApiTestFuzzer::Fuzz();
4970 CHECK_EQ(info.Data(), v8_str("donut"));
4971 CHECK_EQ(name, v8_str("239"));
4972 info.GetReturnValue().Set(name);
4976 THREADED_TEST(ElementAPIAccessor) {
4977 v8::HandleScope scope(v8::Isolate::GetCurrent());
4978 Local<ObjectTemplate> templ = ObjectTemplate::New();
4979 LocalContext context;
4981 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
4982 CompileRun("var obj2 = {};");
4984 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
4988 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
4993 ExpectString("obj1[239]", "239");
4994 ExpectString("obj2[239]", "239");
4995 ExpectString("obj1['239']", "239");
4996 ExpectString("obj2['239']", "239");
5000 v8::Persistent<Value> xValue;
5003 static void SetXValue(Local<String> name,
5005 const v8::PropertyCallbackInfo<void>& info) {
5006 CHECK_EQ(value, v8_num(4));
5007 CHECK_EQ(info.Data(), v8_str("donut"));
5008 CHECK_EQ(name, v8_str("x"));
5009 CHECK(xValue.IsEmpty());
5010 xValue.Reset(info.GetIsolate(), value);
5014 THREADED_TEST(SimplePropertyWrite) {
5015 v8::HandleScope scope(v8::Isolate::GetCurrent());
5016 Local<ObjectTemplate> templ = ObjectTemplate::New();
5017 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5018 LocalContext context;
5019 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5020 Local<Script> script = Script::Compile(v8_str("obj.x = 4"));
5021 for (int i = 0; i < 10; i++) {
5022 CHECK(xValue.IsEmpty());
5024 CHECK_EQ(v8_num(4), Local<Value>::New(v8::Isolate::GetCurrent(), xValue));
5025 xValue.Dispose(context->GetIsolate());
5031 THREADED_TEST(SetterOnly) {
5032 v8::HandleScope scope(v8::Isolate::GetCurrent());
5033 Local<ObjectTemplate> templ = ObjectTemplate::New();
5034 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5035 LocalContext context;
5036 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5037 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5038 for (int i = 0; i < 10; i++) {
5039 CHECK(xValue.IsEmpty());
5041 CHECK_EQ(v8_num(4), Local<Value>::New(v8::Isolate::GetCurrent(), xValue));
5042 xValue.Dispose(context->GetIsolate());
5048 THREADED_TEST(NoAccessors) {
5049 v8::HandleScope scope(v8::Isolate::GetCurrent());
5050 Local<ObjectTemplate> templ = ObjectTemplate::New();
5051 templ->SetAccessor(v8_str("x"),
5052 static_cast<v8::AccessorGetterCallback>(NULL),
5055 LocalContext context;
5056 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5057 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x"));
5058 for (int i = 0; i < 10; i++) {
5064 static void XPropertyGetter(Local<String> property,
5065 const v8::PropertyCallbackInfo<v8::Value>& info) {
5066 ApiTestFuzzer::Fuzz();
5067 CHECK(info.Data()->IsUndefined());
5068 info.GetReturnValue().Set(property);
5072 THREADED_TEST(NamedInterceptorPropertyRead) {
5073 v8::HandleScope scope(v8::Isolate::GetCurrent());
5074 Local<ObjectTemplate> templ = ObjectTemplate::New();
5075 templ->SetNamedPropertyHandler(XPropertyGetter);
5076 LocalContext context;
5077 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5078 Local<Script> script = Script::Compile(v8_str("obj.x"));
5079 for (int i = 0; i < 10; i++) {
5080 Local<Value> result = script->Run();
5081 CHECK_EQ(result, v8_str("x"));
5086 THREADED_TEST(NamedInterceptorDictionaryIC) {
5087 v8::HandleScope scope(v8::Isolate::GetCurrent());
5088 Local<ObjectTemplate> templ = ObjectTemplate::New();
5089 templ->SetNamedPropertyHandler(XPropertyGetter);
5090 LocalContext context;
5091 // Create an object with a named interceptor.
5092 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
5093 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x"));
5094 for (int i = 0; i < 10; i++) {
5095 Local<Value> result = script->Run();
5096 CHECK_EQ(result, v8_str("x"));
5098 // Create a slow case object and a function accessing a property in
5099 // that slow case object (with dictionary probing in generated
5100 // code). Then force object with a named interceptor into slow-case,
5101 // pass it to the function, and check that the interceptor is called
5102 // instead of accessing the local property.
5103 Local<Value> result =
5104 CompileRun("function get_x(o) { return o.x; };"
5105 "var obj = { x : 42, y : 0 };"
5107 "for (var i = 0; i < 10; i++) get_x(obj);"
5108 "interceptor_obj.x = 42;"
5109 "interceptor_obj.y = 10;"
5110 "delete interceptor_obj.y;"
5111 "get_x(interceptor_obj)");
5112 CHECK_EQ(result, v8_str("x"));
5116 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
5117 v8::Isolate* isolate = v8::Isolate::GetCurrent();
5118 v8::HandleScope scope(isolate);
5119 v8::Local<Context> context1 = Context::New(isolate);
5122 Local<ObjectTemplate> templ = ObjectTemplate::New();
5123 templ->SetNamedPropertyHandler(XPropertyGetter);
5124 // Create an object with a named interceptor.
5125 v8::Local<v8::Object> object = templ->NewInstance();
5126 context1->Global()->Set(v8_str("interceptor_obj"), object);
5128 // Force the object into the slow case.
5129 CompileRun("interceptor_obj.y = 0;"
5130 "delete interceptor_obj.y;");
5134 // Introduce the object into a different context.
5135 // Repeat named loads to exercise ICs.
5136 LocalContext context2;
5137 context2->Global()->Set(v8_str("interceptor_obj"), object);
5138 Local<Value> result =
5139 CompileRun("function get_x(o) { return o.x; }"
5140 "interceptor_obj.x = 42;"
5141 "for (var i=0; i != 10; i++) {"
5142 " get_x(interceptor_obj);"
5144 "get_x(interceptor_obj)");
5145 // Check that the interceptor was actually invoked.
5146 CHECK_EQ(result, v8_str("x"));
5149 // Return to the original context and force some object to the slow case
5150 // to cause the NormalizedMapCache to verify.
5152 CompileRun("var obj = { x : 0 }; delete obj.x;");
5157 static void SetXOnPrototypeGetter(
5158 Local<String> property,
5159 const v8::PropertyCallbackInfo<v8::Value>& info) {
5160 // Set x on the prototype object and do not handle the get request.
5161 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
5162 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23));
5166 // This is a regression test for http://crbug.com/20104. Map
5167 // transitions should not interfere with post interceptor lookup.
5168 THREADED_TEST(NamedInterceptorMapTransitionRead) {
5169 v8::HandleScope scope(v8::Isolate::GetCurrent());
5170 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New();
5171 Local<v8::ObjectTemplate> instance_template
5172 = function_template->InstanceTemplate();
5173 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
5174 LocalContext context;
5175 context->Global()->Set(v8_str("F"), function_template->GetFunction());
5176 // Create an instance of F and introduce a map transition for x.
5177 CompileRun("var o = new F(); o.x = 23;");
5178 // Create an instance of F and invoke the getter. The result should be 23.
5179 Local<Value> result = CompileRun("o = new F(); o.x");
5180 CHECK_EQ(result->Int32Value(), 23);
5184 static void IndexedPropertyGetter(
5186 const v8::PropertyCallbackInfo<v8::Value>& info) {
5187 ApiTestFuzzer::Fuzz();
5189 info.GetReturnValue().Set(v8_num(625));
5194 static void IndexedPropertySetter(
5197 const v8::PropertyCallbackInfo<v8::Value>& info) {
5198 ApiTestFuzzer::Fuzz();
5200 info.GetReturnValue().Set(value);
5205 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
5206 v8::HandleScope scope(v8::Isolate::GetCurrent());
5207 Local<ObjectTemplate> templ = ObjectTemplate::New();
5208 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
5209 IndexedPropertySetter);
5210 LocalContext context;
5211 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5212 Local<Script> getter_script = Script::Compile(v8_str(
5213 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];"));
5214 Local<Script> setter_script = Script::Compile(v8_str(
5215 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
5218 Local<Script> interceptor_setter_script = Script::Compile(v8_str(
5219 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
5221 "obj.foo;")); // This setter should not run, due to the interceptor.
5222 Local<Script> interceptor_getter_script = Script::Compile(v8_str(
5224 Local<Value> result = getter_script->Run();
5225 CHECK_EQ(v8_num(5), result);
5226 result = setter_script->Run();
5227 CHECK_EQ(v8_num(23), result);
5228 result = interceptor_setter_script->Run();
5229 CHECK_EQ(v8_num(23), result);
5230 result = interceptor_getter_script->Run();
5231 CHECK_EQ(v8_num(625), result);
5235 static void UnboxedDoubleIndexedPropertyGetter(
5237 const v8::PropertyCallbackInfo<v8::Value>& info) {
5238 ApiTestFuzzer::Fuzz();
5240 info.GetReturnValue().Set(v8_num(index));
5245 static void UnboxedDoubleIndexedPropertySetter(
5248 const v8::PropertyCallbackInfo<v8::Value>& info) {
5249 ApiTestFuzzer::Fuzz();
5251 info.GetReturnValue().Set(v8_num(index));
5256 void UnboxedDoubleIndexedPropertyEnumerator(
5257 const v8::PropertyCallbackInfo<v8::Array>& info) {
5258 // Force the list of returned keys to be stored in a FastDoubleArray.
5259 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5260 "keys = new Array(); keys[125000] = 1;"
5261 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
5262 "keys.length = 25; keys;"));
5263 Local<Value> result = indexed_property_names_script->Run();
5264 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
5268 // Make sure that the the interceptor code in the runtime properly handles
5269 // merging property name lists for double-array-backed arrays.
5270 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
5271 v8::HandleScope scope(v8::Isolate::GetCurrent());
5272 Local<ObjectTemplate> templ = ObjectTemplate::New();
5273 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
5274 UnboxedDoubleIndexedPropertySetter,
5277 UnboxedDoubleIndexedPropertyEnumerator);
5278 LocalContext context;
5279 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5280 // When obj is created, force it to be Stored in a FastDoubleArray.
5281 Local<Script> create_unboxed_double_script = Script::Compile(v8_str(
5282 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
5284 "for (x in obj) {key_count++;};"
5286 Local<Value> result = create_unboxed_double_script->Run();
5287 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
5288 Local<Script> key_count_check = Script::Compile(v8_str(
5290 result = key_count_check->Run();
5291 CHECK_EQ(v8_num(40013), result);
5295 void NonStrictArgsIndexedPropertyEnumerator(
5296 const v8::PropertyCallbackInfo<v8::Array>& info) {
5297 // Force the list of returned keys to be stored in a Arguments object.
5298 Local<Script> indexed_property_names_script = Script::Compile(v8_str(
5300 " return arguments;"
5302 "keys = f(0, 1, 2, 3);"
5304 Local<Object> result =
5305 Local<Object>::Cast(indexed_property_names_script->Run());
5306 // Have to populate the handle manually, as it's not Cast-able.
5307 i::Handle<i::JSObject> o =
5308 v8::Utils::OpenHandle<Object, i::JSObject>(result);
5309 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
5310 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
5314 static void NonStrictIndexedPropertyGetter(
5316 const v8::PropertyCallbackInfo<v8::Value>& info) {
5317 ApiTestFuzzer::Fuzz();
5319 info.GetReturnValue().Set(v8_num(index));
5324 // Make sure that the the interceptor code in the runtime properly handles
5325 // merging property name lists for non-string arguments arrays.
5326 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) {
5327 v8::HandleScope scope(v8::Isolate::GetCurrent());
5328 Local<ObjectTemplate> templ = ObjectTemplate::New();
5329 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter,
5333 NonStrictArgsIndexedPropertyEnumerator);
5334 LocalContext context;
5335 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5336 Local<Script> create_args_script =
5337 Script::Compile(v8_str(
5338 "var key_count = 0;"
5339 "for (x in obj) {key_count++;} key_count;"));
5340 Local<Value> result = create_args_script->Run();
5341 CHECK_EQ(v8_num(4), result);
5345 static void IdentityIndexedPropertyGetter(
5347 const v8::PropertyCallbackInfo<v8::Value>& info) {
5348 info.GetReturnValue().Set(index);
5352 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
5353 v8::HandleScope scope(v8::Isolate::GetCurrent());
5354 Local<ObjectTemplate> templ = ObjectTemplate::New();
5355 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5357 LocalContext context;
5358 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5360 // Check fast object case.
5361 const char* fast_case_code =
5362 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
5363 ExpectString(fast_case_code, "0");
5366 const char* slow_case_code =
5367 "obj.x = 1; delete obj.x;"
5368 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
5369 ExpectString(slow_case_code, "1");
5373 THREADED_TEST(IndexedInterceptorWithNoSetter) {
5374 v8::HandleScope scope(v8::Isolate::GetCurrent());
5375 Local<ObjectTemplate> templ = ObjectTemplate::New();
5376 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5378 LocalContext context;
5379 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5384 " for (var i = 0; i < 100; i++) {"
5386 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
5392 ExpectString(code, "PASSED");
5396 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
5397 v8::HandleScope scope(v8::Isolate::GetCurrent());
5398 Local<ObjectTemplate> templ = ObjectTemplate::New();
5399 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5401 LocalContext context;
5402 Local<v8::Object> obj = templ->NewInstance();
5403 obj->TurnOnAccessCheck();
5404 context->Global()->Set(v8_str("obj"), obj);
5408 " for (var i = 0; i < 100; i++) {"
5410 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;"
5416 ExpectString(code, "PASSED");
5420 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
5421 i::FLAG_allow_natives_syntax = true;
5422 v8::HandleScope scope(v8::Isolate::GetCurrent());
5423 Local<ObjectTemplate> templ = ObjectTemplate::New();
5424 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5426 LocalContext context;
5427 Local<v8::Object> obj = templ->NewInstance();
5428 context->Global()->Set(v8_str("obj"), obj);
5432 " for (var i = 0; i < 100; i++) {"
5433 " var expected = i;"
5435 " %EnableAccessChecks(obj);"
5436 " expected = undefined;"
5439 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5440 " if (i == 5) %DisableAccessChecks(obj);"
5446 ExpectString(code, "PASSED");
5450 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
5451 v8::HandleScope scope(v8::Isolate::GetCurrent());
5452 Local<ObjectTemplate> templ = ObjectTemplate::New();
5453 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5455 LocalContext context;
5456 Local<v8::Object> obj = templ->NewInstance();
5457 context->Global()->Set(v8_str("obj"), obj);
5461 " for (var i = 0; i < 100; i++) {"
5463 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
5469 ExpectString(code, "PASSED");
5473 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
5474 v8::HandleScope scope(v8::Isolate::GetCurrent());
5475 Local<ObjectTemplate> templ = ObjectTemplate::New();
5476 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5478 LocalContext context;
5479 Local<v8::Object> obj = templ->NewInstance();
5480 context->Global()->Set(v8_str("obj"), obj);
5484 " for (var i = 0; i < 100; i++) {"
5485 " var expected = i;"
5489 " expected = undefined;"
5492 " /* probe minimal Smi number on 32-bit platforms */"
5493 " key = -(1 << 30);"
5494 " expected = undefined;"
5497 " /* probe minimal Smi number on 64-bit platforms */"
5499 " expected = undefined;"
5501 " var v = obj[key];"
5502 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5508 ExpectString(code, "PASSED");
5512 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
5513 v8::HandleScope scope(v8::Isolate::GetCurrent());
5514 Local<ObjectTemplate> templ = ObjectTemplate::New();
5515 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5517 LocalContext context;
5518 Local<v8::Object> obj = templ->NewInstance();
5519 context->Global()->Set(v8_str("obj"), obj);
5523 " for (var i = 0; i < 100; i++) {"
5524 " var expected = i;"
5528 " expected = undefined;"
5530 " var v = obj[key];"
5531 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5537 ExpectString(code, "PASSED");
5541 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
5542 v8::HandleScope scope(v8::Isolate::GetCurrent());
5543 Local<ObjectTemplate> templ = ObjectTemplate::New();
5544 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5546 LocalContext context;
5547 Local<v8::Object> obj = templ->NewInstance();
5548 context->Global()->Set(v8_str("obj"), obj);
5551 "var original = obj;"
5553 " for (var i = 0; i < 100; i++) {"
5554 " var expected = i;"
5556 " obj = {50: 'foobar'};"
5557 " expected = 'foobar';"
5560 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5561 " if (i == 50) obj = original;"
5567 ExpectString(code, "PASSED");
5571 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
5572 v8::HandleScope scope(v8::Isolate::GetCurrent());
5573 Local<ObjectTemplate> templ = ObjectTemplate::New();
5574 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5576 LocalContext context;
5577 Local<v8::Object> obj = templ->NewInstance();
5578 context->Global()->Set(v8_str("obj"), obj);
5581 "var original = obj;"
5583 " for (var i = 0; i < 100; i++) {"
5584 " var expected = i;"
5587 " expected = undefined;"
5590 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
5591 " if (i == 5) obj = original;"
5597 ExpectString(code, "PASSED");
5601 THREADED_TEST(IndexedInterceptorOnProto) {
5602 v8::HandleScope scope(v8::Isolate::GetCurrent());
5603 Local<ObjectTemplate> templ = ObjectTemplate::New();
5604 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
5606 LocalContext context;
5607 Local<v8::Object> obj = templ->NewInstance();
5608 context->Global()->Set(v8_str("obj"), obj);
5611 "var o = {__proto__: obj};"
5613 " for (var i = 0; i < 100; i++) {"
5615 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
5621 ExpectString(code, "PASSED");
5625 THREADED_TEST(MultiContexts) {
5626 v8::HandleScope scope(v8::Isolate::GetCurrent());
5627 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New();
5628 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler));
5630 Local<String> password = v8_str("Password");
5632 // Create an environment
5633 LocalContext context0(0, templ);
5634 context0->SetSecurityToken(password);
5635 v8::Handle<v8::Object> global0 = context0->Global();
5636 global0->Set(v8_str("custom"), v8_num(1234));
5637 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5639 // Create an independent environment
5640 LocalContext context1(0, templ);
5641 context1->SetSecurityToken(password);
5642 v8::Handle<v8::Object> global1 = context1->Global();
5643 global1->Set(v8_str("custom"), v8_num(1234));
5644 CHECK_NE(global0, global1);
5645 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5646 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
5648 // Now create a new context with the old global
5649 LocalContext context2(0, templ, global1);
5650 context2->SetSecurityToken(password);
5651 v8::Handle<v8::Object> global2 = context2->Global();
5652 CHECK_EQ(global1, global2);
5653 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
5654 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
5658 THREADED_TEST(FunctionPrototypeAcrossContexts) {
5659 // Make sure that functions created by cloning boilerplates cannot
5660 // communicate through their __proto__ field.
5662 v8::HandleScope scope(v8::Isolate::GetCurrent());
5665 v8::Handle<v8::Object> global0 =
5667 v8::Handle<v8::Object> object0 =
5668 global0->Get(v8_str("Object")).As<v8::Object>();
5669 v8::Handle<v8::Object> tostring0 =
5670 object0->Get(v8_str("toString")).As<v8::Object>();
5671 v8::Handle<v8::Object> proto0 =
5672 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
5673 proto0->Set(v8_str("custom"), v8_num(1234));
5676 v8::Handle<v8::Object> global1 =
5678 v8::Handle<v8::Object> object1 =
5679 global1->Get(v8_str("Object")).As<v8::Object>();
5680 v8::Handle<v8::Object> tostring1 =
5681 object1->Get(v8_str("toString")).As<v8::Object>();
5682 v8::Handle<v8::Object> proto1 =
5683 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
5684 CHECK(!proto1->Has(v8_str("custom")));
5688 THREADED_TEST(Regress892105) {
5689 // Make sure that object and array literals created by cloning
5690 // boilerplates cannot communicate through their __proto__
5691 // field. This is rather difficult to check, but we try to add stuff
5692 // to Object.prototype and Array.prototype and create a new
5693 // environment. This should succeed.
5695 v8::HandleScope scope(v8::Isolate::GetCurrent());
5697 Local<String> source = v8_str("Object.prototype.obj = 1234;"
5698 "Array.prototype.arr = 4567;"
5702 Local<Script> script0 = Script::Compile(source);
5703 CHECK_EQ(8901.0, script0->Run()->NumberValue());
5706 Local<Script> script1 = Script::Compile(source);
5707 CHECK_EQ(8901.0, script1->Run()->NumberValue());
5711 THREADED_TEST(UndetectableObject) {
5713 v8::HandleScope scope(env->GetIsolate());
5715 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
5716 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5718 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5719 env->Global()->Set(v8_str("undetectable"), obj);
5721 ExpectString("undetectable.toString()", "[object Object]");
5722 ExpectString("typeof undetectable", "undefined");
5723 ExpectString("typeof(undetectable)", "undefined");
5724 ExpectBoolean("typeof undetectable == 'undefined'", true);
5725 ExpectBoolean("typeof undetectable == 'object'", false);
5726 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
5727 ExpectBoolean("!undetectable", true);
5729 ExpectObject("true&&undetectable", obj);
5730 ExpectBoolean("false&&undetectable", false);
5731 ExpectBoolean("true||undetectable", true);
5732 ExpectObject("false||undetectable", obj);
5734 ExpectObject("undetectable&&true", obj);
5735 ExpectObject("undetectable&&false", obj);
5736 ExpectBoolean("undetectable||true", true);
5737 ExpectBoolean("undetectable||false", false);
5739 ExpectBoolean("undetectable==null", true);
5740 ExpectBoolean("null==undetectable", true);
5741 ExpectBoolean("undetectable==undefined", true);
5742 ExpectBoolean("undefined==undetectable", true);
5743 ExpectBoolean("undetectable==undetectable", true);
5746 ExpectBoolean("undetectable===null", false);
5747 ExpectBoolean("null===undetectable", false);
5748 ExpectBoolean("undetectable===undefined", false);
5749 ExpectBoolean("undefined===undetectable", false);
5750 ExpectBoolean("undetectable===undetectable", true);
5754 THREADED_TEST(VoidLiteral) {
5756 v8::HandleScope scope(env->GetIsolate());
5758 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
5759 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5761 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5762 env->Global()->Set(v8_str("undetectable"), obj);
5764 ExpectBoolean("undefined == void 0", true);
5765 ExpectBoolean("undetectable == void 0", true);
5766 ExpectBoolean("null == void 0", true);
5767 ExpectBoolean("undefined === void 0", true);
5768 ExpectBoolean("undetectable === void 0", false);
5769 ExpectBoolean("null === void 0", false);
5771 ExpectBoolean("void 0 == undefined", true);
5772 ExpectBoolean("void 0 == undetectable", true);
5773 ExpectBoolean("void 0 == null", true);
5774 ExpectBoolean("void 0 === undefined", true);
5775 ExpectBoolean("void 0 === undetectable", false);
5776 ExpectBoolean("void 0 === null", false);
5778 ExpectString("(function() {"
5780 " return x === void 0;"
5782 " return e.toString();"
5785 "ReferenceError: x is not defined");
5786 ExpectString("(function() {"
5788 " return void 0 === x;"
5790 " return e.toString();"
5793 "ReferenceError: x is not defined");
5797 THREADED_TEST(ExtensibleOnUndetectable) {
5799 v8::HandleScope scope(env->GetIsolate());
5801 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
5802 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5804 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5805 env->Global()->Set(v8_str("undetectable"), obj);
5807 Local<String> source = v8_str("undetectable.x = 42;"
5810 Local<Script> script = Script::Compile(source);
5812 CHECK_EQ(v8::Integer::New(42), script->Run());
5814 ExpectBoolean("Object.isExtensible(undetectable)", true);
5816 source = v8_str("Object.preventExtensions(undetectable);");
5817 script = Script::Compile(source);
5819 ExpectBoolean("Object.isExtensible(undetectable)", false);
5821 source = v8_str("undetectable.y = 2000;");
5822 script = Script::Compile(source);
5824 ExpectBoolean("undetectable.y == undefined", true);
5829 THREADED_TEST(UndetectableString) {
5831 v8::HandleScope scope(env->GetIsolate());
5833 Local<String> obj = String::NewUndetectable("foo");
5834 env->Global()->Set(v8_str("undetectable"), obj);
5836 ExpectString("undetectable", "foo");
5837 ExpectString("typeof undetectable", "undefined");
5838 ExpectString("typeof(undetectable)", "undefined");
5839 ExpectBoolean("typeof undetectable == 'undefined'", true);
5840 ExpectBoolean("typeof undetectable == 'string'", false);
5841 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
5842 ExpectBoolean("!undetectable", true);
5844 ExpectObject("true&&undetectable", obj);
5845 ExpectBoolean("false&&undetectable", false);
5846 ExpectBoolean("true||undetectable", true);
5847 ExpectObject("false||undetectable", obj);
5849 ExpectObject("undetectable&&true", obj);
5850 ExpectObject("undetectable&&false", obj);
5851 ExpectBoolean("undetectable||true", true);
5852 ExpectBoolean("undetectable||false", false);
5854 ExpectBoolean("undetectable==null", true);
5855 ExpectBoolean("null==undetectable", true);
5856 ExpectBoolean("undetectable==undefined", true);
5857 ExpectBoolean("undefined==undetectable", true);
5858 ExpectBoolean("undetectable==undetectable", true);
5861 ExpectBoolean("undetectable===null", false);
5862 ExpectBoolean("null===undetectable", false);
5863 ExpectBoolean("undetectable===undefined", false);
5864 ExpectBoolean("undefined===undetectable", false);
5865 ExpectBoolean("undetectable===undetectable", true);
5869 TEST(UndetectableOptimized) {
5870 i::FLAG_allow_natives_syntax = true;
5872 v8::HandleScope scope(env->GetIsolate());
5874 Local<String> obj = String::NewUndetectable("foo");
5875 env->Global()->Set(v8_str("undetectable"), obj);
5876 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
5879 "function testBranch() {"
5880 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
5881 " if (%_IsUndetectableObject(detectable)) throw 2;"
5883 "function testBool() {"
5884 " var b1 = !%_IsUndetectableObject(undetectable);"
5885 " var b2 = %_IsUndetectableObject(detectable);"
5890 "%OptimizeFunctionOnNextCall(testBranch);"
5891 "%OptimizeFunctionOnNextCall(testBool);"
5892 "for (var i = 0; i < 10; i++) {"
5901 template <typename T> static void USE(T) { }
5904 // This test is not intended to be run, just type checked.
5905 static inline void PersistentHandles(v8::Isolate* isolate) {
5906 USE(PersistentHandles);
5907 Local<String> str = v8_str("foo");
5908 v8::Persistent<String> p_str(isolate, str);
5910 Local<Script> scr = Script::Compile(v8_str(""));
5911 v8::Persistent<Script> p_scr(isolate, scr);
5913 Local<ObjectTemplate> templ = ObjectTemplate::New();
5914 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
5919 static void HandleLogDelegator(
5920 const v8::FunctionCallbackInfo<v8::Value>& args) {
5921 ApiTestFuzzer::Fuzz();
5925 THREADED_TEST(GlobalObjectTemplate) {
5926 v8::Isolate* isolate = v8::Isolate::GetCurrent();
5927 v8::HandleScope handle_scope(isolate);
5928 Local<ObjectTemplate> global_template = ObjectTemplate::New();
5929 global_template->Set(v8_str("JSNI_Log"),
5930 v8::FunctionTemplate::New(HandleLogDelegator));
5931 v8::Local<Context> context = Context::New(isolate, 0, global_template);
5932 Context::Scope context_scope(context);
5933 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run();
5937 static const char* kSimpleExtensionSource =
5943 THREADED_TEST(SimpleExtensions) {
5944 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
5945 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
5946 const char* extension_names[] = { "simpletest" };
5947 v8::ExtensionConfiguration extensions(1, extension_names);
5948 v8::Handle<Context> context =
5949 Context::New(v8::Isolate::GetCurrent(), &extensions);
5950 Context::Scope lock(context);
5951 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
5952 CHECK_EQ(result, v8::Integer::New(4));
5956 THREADED_TEST(NullExtensions) {
5957 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
5958 v8::RegisterExtension(new Extension("nulltest", NULL));
5959 const char* extension_names[] = { "nulltest" };
5960 v8::ExtensionConfiguration extensions(1, extension_names);
5961 v8::Handle<Context> context =
5962 Context::New(v8::Isolate::GetCurrent(), &extensions);
5963 Context::Scope lock(context);
5964 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run();
5965 CHECK_EQ(result, v8::Integer::New(4));
5969 static const char* kEmbeddedExtensionSource =
5970 "function Ret54321(){return 54321;}~~@@$"
5971 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
5972 static const int kEmbeddedExtensionSourceValidLen = 34;
5975 THREADED_TEST(ExtensionMissingSourceLength) {
5976 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
5977 v8::RegisterExtension(new Extension("srclentest_fail",
5978 kEmbeddedExtensionSource));
5979 const char* extension_names[] = { "srclentest_fail" };
5980 v8::ExtensionConfiguration extensions(1, extension_names);
5981 v8::Handle<Context> context =
5982 Context::New(v8::Isolate::GetCurrent(), &extensions);
5983 CHECK_EQ(0, *context);
5987 THREADED_TEST(ExtensionWithSourceLength) {
5988 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
5989 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
5990 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
5991 i::ScopedVector<char> extension_name(32);
5992 i::OS::SNPrintF(extension_name, "ext #%d", source_len);
5993 v8::RegisterExtension(new Extension(extension_name.start(),
5994 kEmbeddedExtensionSource, 0, 0,
5996 const char* extension_names[1] = { extension_name.start() };
5997 v8::ExtensionConfiguration extensions(1, extension_names);
5998 v8::Handle<Context> context =
5999 Context::New(v8::Isolate::GetCurrent(), &extensions);
6000 if (source_len == kEmbeddedExtensionSourceValidLen) {
6001 Context::Scope lock(context);
6002 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run();
6003 CHECK_EQ(v8::Integer::New(54321), result);
6005 // Anything but exactly the right length should fail to compile.
6006 CHECK_EQ(0, *context);
6012 static const char* kEvalExtensionSource1 =
6013 "function UseEval1() {"
6015 " return eval('x');"
6019 static const char* kEvalExtensionSource2 =
6023 " return eval('x');"
6025 " this.UseEval2 = e;"
6029 THREADED_TEST(UseEvalFromExtension) {
6030 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6031 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6032 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6033 const char* extension_names[] = { "evaltest1", "evaltest2" };
6034 v8::ExtensionConfiguration extensions(2, extension_names);
6035 v8::Handle<Context> context =
6036 Context::New(v8::Isolate::GetCurrent(), &extensions);
6037 Context::Scope lock(context);
6038 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run();
6039 CHECK_EQ(result, v8::Integer::New(42));
6040 result = Script::Compile(v8_str("UseEval2()"))->Run();
6041 CHECK_EQ(result, v8::Integer::New(42));
6045 static const char* kWithExtensionSource1 =
6046 "function UseWith1() {"
6048 " with({x:87}) { return x; }"
6053 static const char* kWithExtensionSource2 =
6057 " with ({x:87}) { return x; }"
6059 " this.UseWith2 = e;"
6063 THREADED_TEST(UseWithFromExtension) {
6064 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6065 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6066 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6067 const char* extension_names[] = { "withtest1", "withtest2" };
6068 v8::ExtensionConfiguration extensions(2, extension_names);
6069 v8::Handle<Context> context =
6070 Context::New(v8::Isolate::GetCurrent(), &extensions);
6071 Context::Scope lock(context);
6072 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run();
6073 CHECK_EQ(result, v8::Integer::New(87));
6074 result = Script::Compile(v8_str("UseWith2()"))->Run();
6075 CHECK_EQ(result, v8::Integer::New(87));
6079 THREADED_TEST(AutoExtensions) {
6080 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6081 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6082 extension->set_auto_enable(true);
6083 v8::RegisterExtension(extension);
6084 v8::Handle<Context> context =
6085 Context::New(v8::Isolate::GetCurrent());
6086 Context::Scope lock(context);
6087 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run();
6088 CHECK_EQ(result, v8::Integer::New(4));
6092 static const char* kSyntaxErrorInExtensionSource =
6096 // Test that a syntax error in an extension does not cause a fatal
6097 // error but results in an empty context.
6098 THREADED_TEST(SyntaxErrorExtensions) {
6099 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6100 v8::RegisterExtension(new Extension("syntaxerror",
6101 kSyntaxErrorInExtensionSource));
6102 const char* extension_names[] = { "syntaxerror" };
6103 v8::ExtensionConfiguration extensions(1, extension_names);
6104 v8::Handle<Context> context =
6105 Context::New(v8::Isolate::GetCurrent(), &extensions);
6106 CHECK(context.IsEmpty());
6110 static const char* kExceptionInExtensionSource =
6114 // Test that an exception when installing an extension does not cause
6115 // a fatal error but results in an empty context.
6116 THREADED_TEST(ExceptionExtensions) {
6117 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6118 v8::RegisterExtension(new Extension("exception",
6119 kExceptionInExtensionSource));
6120 const char* extension_names[] = { "exception" };
6121 v8::ExtensionConfiguration extensions(1, extension_names);
6122 v8::Handle<Context> context =
6123 Context::New(v8::Isolate::GetCurrent(), &extensions);
6124 CHECK(context.IsEmpty());
6128 static const char* kNativeCallInExtensionSource =
6129 "function call_runtime_last_index_of(x) {"
6130 " return %StringLastIndexOf(x, 'bob', 10);"
6134 static const char* kNativeCallTest =
6135 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6137 // Test that a native runtime calls are supported in extensions.
6138 THREADED_TEST(NativeCallInExtensions) {
6139 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6140 v8::RegisterExtension(new Extension("nativecall",
6141 kNativeCallInExtensionSource));
6142 const char* extension_names[] = { "nativecall" };
6143 v8::ExtensionConfiguration extensions(1, extension_names);
6144 v8::Handle<Context> context =
6145 Context::New(v8::Isolate::GetCurrent(), &extensions);
6146 Context::Scope lock(context);
6147 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run();
6148 CHECK_EQ(result, v8::Integer::New(3));
6152 class NativeFunctionExtension : public Extension {
6154 NativeFunctionExtension(const char* name,
6156 v8::FunctionCallback fun = &Echo)
6157 : Extension(name, source),
6160 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
6161 v8::Handle<v8::String> name) {
6162 return v8::FunctionTemplate::New(function_);
6165 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6166 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6169 v8::FunctionCallback function_;
6173 THREADED_TEST(NativeFunctionDeclaration) {
6174 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6175 const char* name = "nativedecl";
6176 v8::RegisterExtension(new NativeFunctionExtension(name,
6177 "native function foo();"));
6178 const char* extension_names[] = { name };
6179 v8::ExtensionConfiguration extensions(1, extension_names);
6180 v8::Handle<Context> context =
6181 Context::New(v8::Isolate::GetCurrent(), &extensions);
6182 Context::Scope lock(context);
6183 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run();
6184 CHECK_EQ(result, v8::Integer::New(42));
6188 THREADED_TEST(NativeFunctionDeclarationError) {
6189 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6190 const char* name = "nativedeclerr";
6191 // Syntax error in extension code.
6192 v8::RegisterExtension(new NativeFunctionExtension(name,
6193 "native\nfunction foo();"));
6194 const char* extension_names[] = { name };
6195 v8::ExtensionConfiguration extensions(1, extension_names);
6196 v8::Handle<Context> context =
6197 Context::New(v8::Isolate::GetCurrent(), &extensions);
6198 CHECK(context.IsEmpty());
6202 THREADED_TEST(NativeFunctionDeclarationErrorEscape) {
6203 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6204 const char* name = "nativedeclerresc";
6205 // Syntax error in extension code - escape code in "native" means that
6206 // it's not treated as a keyword.
6207 v8::RegisterExtension(new NativeFunctionExtension(
6209 "nativ\\u0065 function foo();"));
6210 const char* extension_names[] = { name };
6211 v8::ExtensionConfiguration extensions(1, extension_names);
6212 v8::Handle<Context> context =
6213 Context::New(v8::Isolate::GetCurrent(), &extensions);
6214 CHECK(context.IsEmpty());
6218 static void CheckDependencies(const char* name, const char* expected) {
6219 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6220 v8::ExtensionConfiguration config(1, &name);
6221 LocalContext context(&config);
6222 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded")));
6233 THREADED_TEST(ExtensionDependency) {
6234 static const char* kEDeps[] = { "D" };
6235 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6236 static const char* kDDeps[] = { "B", "C" };
6237 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6238 static const char* kBCDeps[] = { "A" };
6239 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6240 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6241 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6242 CheckDependencies("A", "undefinedA");
6243 CheckDependencies("B", "undefinedAB");
6244 CheckDependencies("C", "undefinedAC");
6245 CheckDependencies("D", "undefinedABCD");
6246 CheckDependencies("E", "undefinedABCDE");
6247 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6248 static const char* exts[2] = { "C", "E" };
6249 v8::ExtensionConfiguration config(2, exts);
6250 LocalContext context(&config);
6251 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
6255 static const char* kExtensionTestScript =
6256 "native function A();"
6257 "native function B();"
6258 "native function C();"
6260 " if (i == 0) return A();"
6261 " if (i == 1) return B();"
6262 " if (i == 2) return C();"
6266 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6267 ApiTestFuzzer::Fuzz();
6268 if (args.IsConstructCall()) {
6269 args.This()->Set(v8_str("data"), args.Data());
6270 args.GetReturnValue().SetNull();
6273 args.GetReturnValue().Set(args.Data());
6277 class FunctionExtension : public Extension {
6279 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
6280 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
6281 v8::Handle<String> name);
6285 static int lookup_count = 0;
6286 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction(
6287 v8::Handle<String> name) {
6289 if (name->Equals(v8_str("A"))) {
6290 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8));
6291 } else if (name->Equals(v8_str("B"))) {
6292 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7));
6293 } else if (name->Equals(v8_str("C"))) {
6294 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6));
6296 return v8::Handle<v8::FunctionTemplate>();
6301 THREADED_TEST(FunctionLookup) {
6302 v8::RegisterExtension(new FunctionExtension());
6303 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6304 static const char* exts[1] = { "functiontest" };
6305 v8::ExtensionConfiguration config(1, exts);
6306 LocalContext context(&config);
6307 CHECK_EQ(3, lookup_count);
6308 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run());
6309 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run());
6310 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run());
6314 THREADED_TEST(NativeFunctionConstructCall) {
6315 v8::RegisterExtension(new FunctionExtension());
6316 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6317 static const char* exts[1] = { "functiontest" };
6318 v8::ExtensionConfiguration config(1, exts);
6319 LocalContext context(&config);
6320 for (int i = 0; i < 10; i++) {
6321 // Run a few times to ensure that allocation of objects doesn't
6322 // change behavior of a constructor function.
6323 CHECK_EQ(v8::Integer::New(8),
6324 Script::Compile(v8_str("(new A()).data"))->Run());
6325 CHECK_EQ(v8::Integer::New(7),
6326 Script::Compile(v8_str("(new B()).data"))->Run());
6327 CHECK_EQ(v8::Integer::New(6),
6328 Script::Compile(v8_str("(new C()).data"))->Run());
6333 static const char* last_location;
6334 static const char* last_message;
6335 void StoringErrorCallback(const char* location, const char* message) {
6336 if (last_location == NULL) {
6337 last_location = location;
6338 last_message = message;
6343 // ErrorReporting creates a circular extensions configuration and
6344 // tests that the fatal error handler gets called. This renders V8
6345 // unusable and therefore this test cannot be run in parallel.
6346 TEST(ErrorReporting) {
6347 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
6348 static const char* aDeps[] = { "B" };
6349 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
6350 static const char* bDeps[] = { "A" };
6351 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
6352 last_location = NULL;
6353 v8::ExtensionConfiguration config(1, bDeps);
6354 v8::Handle<Context> context =
6355 Context::New(v8::Isolate::GetCurrent(), &config);
6356 CHECK(context.IsEmpty());
6357 CHECK_NE(last_location, NULL);
6361 static const char* js_code_causing_huge_string_flattening =
6363 "for (var i = 0; i < 30; i++) {"
6369 void OOMCallback(const char* location, const char* message) {
6374 TEST(RegexpOutOfMemory) {
6375 // Execute a script that causes out of memory when flattening a string.
6376 v8::HandleScope scope(v8::Isolate::GetCurrent());
6377 v8::V8::SetFatalErrorHandler(OOMCallback);
6378 LocalContext context;
6379 Local<Script> script =
6380 Script::Compile(String::New(js_code_causing_huge_string_flattening));
6381 last_location = NULL;
6384 CHECK(false); // Should not return.
6388 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
6389 v8::Handle<Value> data) {
6390 CHECK(message->GetScriptResourceName()->IsUndefined());
6391 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName());
6392 message->GetLineNumber();
6393 message->GetSourceLine();
6397 THREADED_TEST(ErrorWithMissingScriptInfo) {
6398 LocalContext context;
6399 v8::HandleScope scope(context->GetIsolate());
6400 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
6401 Script::Compile(v8_str("throw Error()"))->Run();
6402 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
6406 int global_index = 0;
6410 Snorkel() { index_ = global_index++; }
6416 explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { }
6417 ~Whammy() { script_.Dispose(isolate_); }
6418 v8::Handle<Script> getScript() {
6419 if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo"));
6420 return Local<Script>::New(isolate_, script_);
6424 static const int kObjectCount = 256;
6426 v8::Isolate* isolate_;
6427 v8::Persistent<v8::Object> objects_[kObjectCount];
6428 v8::Persistent<Script> script_;
6431 static void HandleWeakReference(v8::Isolate* isolate,
6432 v8::Persistent<v8::Value>* obj,
6435 obj->ClearWeak(isolate);
6438 void WhammyPropertyGetter(Local<String> name,
6439 const v8::PropertyCallbackInfo<v8::Value>& info) {
6441 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value());
6443 v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_];
6445 v8::Handle<v8::Object> obj = v8::Object::New();
6446 if (!prev.IsEmpty()) {
6447 v8::Local<v8::Object>::New(info.GetIsolate(), prev)
6448 ->Set(v8_str("next"), obj);
6449 prev.MakeWeak<Value, Snorkel>(new Snorkel(), &HandleWeakReference);
6450 whammy->objects_[whammy->cursor_].Clear();
6452 whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj);
6453 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount;
6454 info.GetReturnValue().Set(whammy->getScript()->Run());
6458 THREADED_TEST(WeakReference) {
6459 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
6460 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New();
6461 Whammy* whammy = new Whammy(v8::Isolate::GetCurrent());
6462 templ->SetNamedPropertyHandler(WhammyPropertyGetter,
6464 v8::External::New(whammy));
6465 const char* extension_list[] = { "v8/gc" };
6466 v8::ExtensionConfiguration extensions(1, extension_list);
6467 v8::Handle<Context> context =
6468 Context::New(v8::Isolate::GetCurrent(), &extensions);
6469 Context::Scope context_scope(context);
6471 v8::Handle<v8::Object> interceptor = templ->NewInstance();
6472 context->Global()->Set(v8_str("whammy"), interceptor);
6475 "for (var i = 0; i < 10000; i++) {"
6476 " var obj = whammy.length;"
6477 " if (last) last.next = obj;"
6482 v8::Handle<Value> result = CompileRun(code);
6483 CHECK_EQ(4.0, result->NumberValue());
6488 static void DisposeAndSetFlag(v8::Isolate* isolate,
6489 v8::Persistent<v8::Object>* obj,
6491 obj->Dispose(isolate);
6496 THREADED_TEST(IndependentWeakHandle) {
6497 v8::Isolate* iso = v8::Isolate::GetCurrent();
6498 v8::HandleScope scope(iso);
6499 v8::Handle<Context> context = Context::New(iso);
6500 Context::Scope context_scope(context);
6502 v8::Persistent<v8::Object> object_a, object_b;
6505 v8::HandleScope handle_scope(iso);
6506 object_a.Reset(iso, v8::Object::New());
6507 object_b.Reset(iso, v8::Object::New());
6510 bool object_a_disposed = false;
6511 bool object_b_disposed = false;
6512 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
6513 object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag);
6514 CHECK(!object_b.IsIndependent(iso));
6515 object_a.MarkIndependent(iso);
6516 object_b.MarkIndependent(iso);
6517 CHECK(object_b.IsIndependent(iso));
6518 HEAP->PerformScavenge();
6519 CHECK(object_a_disposed);
6520 CHECK(object_b_disposed);
6524 static void InvokeScavenge() {
6525 HEAP->PerformScavenge();
6529 static void InvokeMarkSweep() {
6530 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
6534 static void ForceScavenge(v8::Isolate* isolate,
6535 v8::Persistent<v8::Object>* obj,
6537 obj->Dispose(isolate);
6543 static void ForceMarkSweep(v8::Isolate* isolate,
6544 v8::Persistent<v8::Object>* obj,
6546 obj->Dispose(isolate);
6552 THREADED_TEST(GCFromWeakCallbacks) {
6553 v8::Isolate* isolate = v8::Isolate::GetCurrent();
6554 v8::HandleScope scope(isolate);
6555 v8::Handle<Context> context = Context::New(isolate);
6556 Context::Scope context_scope(context);
6558 static const int kNumberOfGCTypes = 2;
6559 typedef v8::WeakReferenceCallbacks<v8::Object, bool>::Revivable Callback;
6560 Callback gc_forcing_callback[kNumberOfGCTypes] =
6561 {&ForceScavenge, &ForceMarkSweep};
6563 typedef void (*GCInvoker)();
6564 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
6566 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
6567 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
6568 v8::Persistent<v8::Object> object;
6570 v8::HandleScope handle_scope(isolate);
6571 object.Reset(isolate, v8::Object::New());
6573 bool disposed = false;
6574 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]);
6575 object.MarkIndependent(isolate);
6576 invoke_gc[outer_gc]();
6583 static void RevivingCallback(v8::Isolate* isolate,
6584 v8::Persistent<v8::Object>* obj,
6586 obj->ClearWeak(isolate);
6591 THREADED_TEST(IndependentHandleRevival) {
6592 v8::Isolate* isolate = v8::Isolate::GetCurrent();
6593 v8::HandleScope scope(isolate);
6594 v8::Handle<Context> context = Context::New(isolate);
6595 Context::Scope context_scope(context);
6597 v8::Persistent<v8::Object> object;
6599 v8::HandleScope handle_scope(isolate);
6600 v8::Local<v8::Object> o = v8::Object::New();
6601 object.Reset(isolate, o);
6602 o->Set(v8_str("x"), v8::Integer::New(1));
6603 v8::Local<String> y_str = v8_str("y");
6604 o->Set(y_str, y_str);
6606 bool revived = false;
6607 object.MakeWeak(&revived, &RevivingCallback);
6608 object.MarkIndependent(isolate);
6609 HEAP->PerformScavenge();
6611 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
6613 v8::HandleScope handle_scope(isolate);
6614 v8::Local<v8::Object> o = v8::Local<v8::Object>::New(isolate, object);
6615 v8::Local<String> y_str = v8_str("y");
6616 CHECK_EQ(v8::Integer::New(1), o->Get(v8_str("x")));
6617 CHECK(o->Get(y_str)->Equals(y_str));
6622 v8::Handle<Function> args_fun;
6625 static void ArgumentsTestCallback(
6626 const v8::FunctionCallbackInfo<v8::Value>& args) {
6627 ApiTestFuzzer::Fuzz();
6628 CHECK_EQ(args_fun, args.Callee());
6629 CHECK_EQ(3, args.Length());
6630 CHECK_EQ(v8::Integer::New(1), args[0]);
6631 CHECK_EQ(v8::Integer::New(2), args[1]);
6632 CHECK_EQ(v8::Integer::New(3), args[2]);
6633 CHECK_EQ(v8::Undefined(), args[3]);
6634 v8::HandleScope scope(args.GetIsolate());
6635 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
6639 THREADED_TEST(Arguments) {
6640 v8::HandleScope scope(v8::Isolate::GetCurrent());
6641 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New();
6642 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback));
6643 LocalContext context(NULL, global);
6644 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
6645 v8_compile("f(1, 2, 3)")->Run();
6649 static void NoBlockGetterX(Local<String> name,
6650 const v8::PropertyCallbackInfo<v8::Value>&) {
6654 static void NoBlockGetterI(uint32_t index,
6655 const v8::PropertyCallbackInfo<v8::Value>&) {
6659 static void PDeleter(Local<String> name,
6660 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
6661 if (!name->Equals(v8_str("foo"))) {
6662 return; // not intercepted
6665 info.GetReturnValue().Set(false); // intercepted, don't delete the property
6669 static void IDeleter(uint32_t index,
6670 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
6672 return; // not intercepted
6675 info.GetReturnValue().Set(false); // intercepted, don't delete the property
6679 THREADED_TEST(Deleter) {
6680 v8::HandleScope scope(v8::Isolate::GetCurrent());
6681 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6682 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
6683 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
6684 LocalContext context;
6685 context->Global()->Set(v8_str("k"), obj->NewInstance());
6691 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
6692 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
6694 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
6695 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
6697 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
6698 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
6700 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
6701 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
6705 static void GetK(Local<String> name,
6706 const v8::PropertyCallbackInfo<v8::Value>& info) {
6707 ApiTestFuzzer::Fuzz();
6708 if (name->Equals(v8_str("foo")) ||
6709 name->Equals(v8_str("bar")) ||
6710 name->Equals(v8_str("baz"))) {
6711 info.GetReturnValue().SetUndefined();
6716 static void IndexedGetK(uint32_t index,
6717 const v8::PropertyCallbackInfo<v8::Value>& info) {
6718 ApiTestFuzzer::Fuzz();
6719 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
6723 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
6724 ApiTestFuzzer::Fuzz();
6725 v8::Handle<v8::Array> result = v8::Array::New(3);
6726 result->Set(v8::Integer::New(0), v8_str("foo"));
6727 result->Set(v8::Integer::New(1), v8_str("bar"));
6728 result->Set(v8::Integer::New(2), v8_str("baz"));
6729 info.GetReturnValue().Set(result);
6733 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
6734 ApiTestFuzzer::Fuzz();
6735 v8::Handle<v8::Array> result = v8::Array::New(2);
6736 result->Set(v8::Integer::New(0), v8_str("0"));
6737 result->Set(v8::Integer::New(1), v8_str("1"));
6738 info.GetReturnValue().Set(result);
6742 THREADED_TEST(Enumerators) {
6743 v8::HandleScope scope(v8::Isolate::GetCurrent());
6744 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6745 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
6746 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
6747 LocalContext context;
6748 context->Global()->Set(v8_str("k"), obj->NewInstance());
6749 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
6754 "k[4294967295] = 0;"
6756 "k[4294967296] = 0;"
6760 "k[30000000000] = 0;"
6763 "for (var prop in k) {"
6764 " result.push(prop);"
6767 // Check that we get all the property names returned including the
6768 // ones from the enumerators in the right order: indexed properties
6769 // in numerical order, indexed interceptor properties, named
6770 // properties in insertion order, named interceptor properties.
6771 // This order is not mandated by the spec, so this test is just
6772 // documenting our behavior.
6773 CHECK_EQ(17, result->Length());
6774 // Indexed properties in numerical order.
6775 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0)));
6776 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1)));
6777 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2)));
6778 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3)));
6779 // Indexed interceptor properties in the order they are returned
6780 // from the enumerator interceptor.
6781 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4)));
6782 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5)));
6783 // Named properties in insertion order.
6784 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6)));
6785 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7)));
6786 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8)));
6787 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9)));
6788 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10)));
6789 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11)));
6790 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12)));
6791 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13)));
6792 // Named interceptor properties.
6793 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14)));
6794 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15)));
6795 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16)));
6800 int p_getter_count2;
6803 static void PGetter(Local<String> name,
6804 const v8::PropertyCallbackInfo<v8::Value>& info) {
6805 ApiTestFuzzer::Fuzz();
6807 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
6808 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
6809 if (name->Equals(v8_str("p1"))) {
6810 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
6811 } else if (name->Equals(v8_str("p2"))) {
6812 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
6813 } else if (name->Equals(v8_str("p3"))) {
6814 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
6815 } else if (name->Equals(v8_str("p4"))) {
6816 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
6821 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
6822 ApiTestFuzzer::Fuzz();
6823 LocalContext context;
6824 context->Global()->Set(v8_str("o1"), obj->NewInstance());
6826 "o1.__proto__ = { };"
6827 "var o2 = { __proto__: o1 };"
6828 "var o3 = { __proto__: o2 };"
6829 "var o4 = { __proto__: o3 };"
6830 "for (var i = 0; i < 10; i++) o4.p4;"
6831 "for (var i = 0; i < 10; i++) o3.p3;"
6832 "for (var i = 0; i < 10; i++) o2.p2;"
6833 "for (var i = 0; i < 10; i++) o1.p1;");
6837 static void PGetter2(Local<String> name,
6838 const v8::PropertyCallbackInfo<v8::Value>& info) {
6839 ApiTestFuzzer::Fuzz();
6841 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
6842 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
6843 if (name->Equals(v8_str("p1"))) {
6844 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
6845 } else if (name->Equals(v8_str("p2"))) {
6846 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
6847 } else if (name->Equals(v8_str("p3"))) {
6848 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
6849 } else if (name->Equals(v8_str("p4"))) {
6850 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
6855 THREADED_TEST(GetterHolders) {
6856 v8::HandleScope scope(v8::Isolate::GetCurrent());
6857 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6858 obj->SetAccessor(v8_str("p1"), PGetter);
6859 obj->SetAccessor(v8_str("p2"), PGetter);
6860 obj->SetAccessor(v8_str("p3"), PGetter);
6861 obj->SetAccessor(v8_str("p4"), PGetter);
6864 CHECK_EQ(40, p_getter_count);
6868 THREADED_TEST(PreInterceptorHolders) {
6869 v8::HandleScope scope(v8::Isolate::GetCurrent());
6870 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
6871 obj->SetNamedPropertyHandler(PGetter2);
6872 p_getter_count2 = 0;
6874 CHECK_EQ(40, p_getter_count2);
6878 THREADED_TEST(ObjectInstantiation) {
6879 v8::HandleScope scope(v8::Isolate::GetCurrent());
6880 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
6881 templ->SetAccessor(v8_str("t"), PGetter2);
6882 LocalContext context;
6883 context->Global()->Set(v8_str("o"), templ->NewInstance());
6884 for (int i = 0; i < 100; i++) {
6885 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
6886 v8::Handle<v8::Object> obj = templ->NewInstance();
6887 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
6888 context->Global()->Set(v8_str("o2"), obj);
6889 v8::Handle<Value> value =
6890 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run();
6891 CHECK_EQ(v8::True(), value);
6892 context->Global()->Set(v8_str("o"), obj);
6897 static int StrCmp16(uint16_t* a, uint16_t* b) {
6899 if (*a == 0 && *b == 0) return 0;
6900 if (*a != *b) return 0 + *a - *b;
6907 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
6909 if (n-- == 0) return 0;
6910 if (*a == 0 && *b == 0) return 0;
6911 if (*a != *b) return 0 + *a - *b;
6918 int GetUtf8Length(Handle<String> str) {
6919 int len = str->Utf8Length();
6921 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
6922 i::FlattenString(istr);
6923 len = str->Utf8Length();
6929 THREADED_TEST(StringWrite) {
6930 LocalContext context;
6931 v8::HandleScope scope(context->GetIsolate());
6932 v8::Handle<String> str = v8_str("abcde");
6933 // abc<Icelandic eth><Unicode snowman>.
6934 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
6935 v8::Handle<String> str3 = v8::String::New("abc\0def", 7);
6936 const int kStride = 4; // Must match stride in for loops in JS below.
6939 "for (var i = 0; i < 0xd800; i += 4) {"
6940 " left = left + String.fromCharCode(i);"
6944 "for (var i = 0; i < 0xd800; i += 4) {"
6945 " right = String.fromCharCode(i) + right;"
6947 v8::Handle<v8::Object> global = Context::GetCurrent()->Global();
6948 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
6949 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
6951 CHECK_EQ(5, str2->Length());
6952 CHECK_EQ(0xd800 / kStride, left_tree->Length());
6953 CHECK_EQ(0xd800 / kStride, right_tree->Length());
6956 char utf8buf[0xd800 * 3];
6961 memset(utf8buf, 0x1, 1000);
6962 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
6964 CHECK_EQ(5, charlen);
6965 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
6967 memset(utf8buf, 0x1, 1000);
6968 len = str2->WriteUtf8(utf8buf, 8, &charlen);
6970 CHECK_EQ(5, charlen);
6971 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
6973 memset(utf8buf, 0x1, 1000);
6974 len = str2->WriteUtf8(utf8buf, 7, &charlen);
6976 CHECK_EQ(4, charlen);
6977 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
6979 memset(utf8buf, 0x1, 1000);
6980 len = str2->WriteUtf8(utf8buf, 6, &charlen);
6982 CHECK_EQ(4, charlen);
6983 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
6985 memset(utf8buf, 0x1, 1000);
6986 len = str2->WriteUtf8(utf8buf, 5, &charlen);
6988 CHECK_EQ(4, charlen);
6989 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
6991 memset(utf8buf, 0x1, 1000);
6992 len = str2->WriteUtf8(utf8buf, 4, &charlen);
6994 CHECK_EQ(3, charlen);
6995 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
6997 memset(utf8buf, 0x1, 1000);
6998 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7000 CHECK_EQ(3, charlen);
7001 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7003 memset(utf8buf, 0x1, 1000);
7004 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7006 CHECK_EQ(2, charlen);
7007 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7009 memset(utf8buf, 0x1, sizeof(utf8buf));
7010 len = GetUtf8Length(left_tree);
7012 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7013 CHECK_EQ(utf8_expected, len);
7014 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7015 CHECK_EQ(utf8_expected, len);
7016 CHECK_EQ(0xd800 / kStride, charlen);
7017 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7018 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7019 CHECK_EQ(0xc0 - kStride,
7020 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7021 CHECK_EQ(1, utf8buf[utf8_expected]);
7023 memset(utf8buf, 0x1, sizeof(utf8buf));
7024 len = GetUtf8Length(right_tree);
7025 CHECK_EQ(utf8_expected, len);
7026 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7027 CHECK_EQ(utf8_expected, len);
7028 CHECK_EQ(0xd800 / kStride, charlen);
7029 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7030 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7031 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7032 CHECK_EQ(1, utf8buf[utf8_expected]);
7034 memset(buf, 0x1, sizeof(buf));
7035 memset(wbuf, 0x1, sizeof(wbuf));
7036 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7038 len = str->Write(wbuf);
7040 CHECK_EQ(0, strcmp("abcde", buf));
7041 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7042 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7044 memset(buf, 0x1, sizeof(buf));
7045 memset(wbuf, 0x1, sizeof(wbuf));
7046 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7048 len = str->Write(wbuf, 0, 4);
7050 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7051 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7052 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7054 memset(buf, 0x1, sizeof(buf));
7055 memset(wbuf, 0x1, sizeof(wbuf));
7056 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7058 len = str->Write(wbuf, 0, 5);
7060 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7061 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7062 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7064 memset(buf, 0x1, sizeof(buf));
7065 memset(wbuf, 0x1, sizeof(wbuf));
7066 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7068 len = str->Write(wbuf, 0, 6);
7070 CHECK_EQ(0, strcmp("abcde", buf));
7071 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7072 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7074 memset(buf, 0x1, sizeof(buf));
7075 memset(wbuf, 0x1, sizeof(wbuf));
7076 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7078 len = str->Write(wbuf, 4, -1);
7080 CHECK_EQ(0, strcmp("e", buf));
7081 uint16_t answer5[] = {'e', '\0'};
7082 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7084 memset(buf, 0x1, sizeof(buf));
7085 memset(wbuf, 0x1, sizeof(wbuf));
7086 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7088 len = str->Write(wbuf, 4, 6);
7090 CHECK_EQ(0, strcmp("e", buf));
7091 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7093 memset(buf, 0x1, sizeof(buf));
7094 memset(wbuf, 0x1, sizeof(wbuf));
7095 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7097 len = str->Write(wbuf, 4, 1);
7099 CHECK_EQ(0, strncmp("e\1", buf, 2));
7100 uint16_t answer6[] = {'e', 0x101};
7101 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7103 memset(buf, 0x1, sizeof(buf));
7104 memset(wbuf, 0x1, sizeof(wbuf));
7105 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7107 len = str->Write(wbuf, 3, 1);
7109 CHECK_EQ(0, strncmp("d\1", buf, 2));
7110 uint16_t answer7[] = {'d', 0x101};
7111 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7113 memset(wbuf, 0x1, sizeof(wbuf));
7115 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7117 CHECK_EQ('X', wbuf[5]);
7118 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7119 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7120 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7121 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7123 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7125 memset(buf, 0x1, sizeof(buf));
7127 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7130 String::NO_NULL_TERMINATION);
7132 CHECK_EQ('X', buf[5]);
7133 CHECK_EQ(0, strncmp("abcde", buf, 5));
7134 CHECK_NE(0, strcmp("abcde", buf));
7136 CHECK_EQ(0, strcmp("abcde", buf));
7138 memset(utf8buf, 0x1, sizeof(utf8buf));
7140 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7141 String::NO_NULL_TERMINATION);
7143 CHECK_EQ('X', utf8buf[8]);
7144 CHECK_EQ(5, charlen);
7145 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7146 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7148 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7150 memset(utf8buf, 0x1, sizeof(utf8buf));
7152 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7153 String::NO_NULL_TERMINATION);
7155 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7156 CHECK_EQ(5, charlen);
7158 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7160 memset(buf, 0x1, sizeof(buf));
7161 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7163 CHECK_EQ(0, strcmp("abc", buf));
7164 CHECK_EQ(0, buf[3]);
7165 CHECK_EQ(0, strcmp("def", buf + 4));
7167 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7168 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7169 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7173 static void Utf16Helper(
7174 LocalContext& context,
7176 const char* lengths_name,
7178 Local<v8::Array> a =
7179 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7180 Local<v8::Array> alens =
7181 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7182 for (int i = 0; i < len; i++) {
7183 Local<v8::String> string =
7184 Local<v8::String>::Cast(a->Get(i));
7185 Local<v8::Number> expected_len =
7186 Local<v8::Number>::Cast(alens->Get(i));
7187 int length = GetUtf8Length(string);
7188 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7193 static uint16_t StringGet(Handle<String> str, int index) {
7194 i::Handle<i::String> istring =
7195 v8::Utils::OpenHandle(String::Cast(*str));
7196 return istring->Get(index);
7200 static void WriteUtf8Helper(
7201 LocalContext& context,
7203 const char* lengths_name,
7205 Local<v8::Array> b =
7206 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7207 Local<v8::Array> alens =
7208 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7211 for (int i = 0; i < len; i++) {
7212 Local<v8::String> string =
7213 Local<v8::String>::Cast(b->Get(i));
7214 Local<v8::Number> expected_len =
7215 Local<v8::Number>::Cast(alens->Get(i));
7216 int utf8_length = static_cast<int>(expected_len->Value());
7217 for (int j = utf8_length + 1; j >= 0; j--) {
7218 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7219 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7222 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7224 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7225 CHECK_GE(utf8_length + 1, utf8_written);
7226 CHECK_GE(utf8_length, utf8_written2);
7227 for (int k = 0; k < utf8_written2; k++) {
7228 CHECK_EQ(buffer[k], buffer2[k]);
7230 CHECK(nchars * 3 >= utf8_written - 1);
7231 CHECK(nchars <= utf8_written);
7232 if (j == utf8_length + 1) {
7233 CHECK_EQ(utf8_written2, utf8_length);
7234 CHECK_EQ(utf8_written2 + 1, utf8_written);
7236 CHECK_EQ(buffer[utf8_written], 42);
7237 if (j > utf8_length) {
7238 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7239 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7240 Handle<String> roundtrip = v8_str(buffer);
7241 CHECK(roundtrip->Equals(string));
7243 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7245 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7247 uint16_t trail = StringGet(string, nchars - 1);
7248 uint16_t lead = StringGet(string, nchars - 2);
7249 if (((lead & 0xfc00) == 0xd800) &&
7250 ((trail & 0xfc00) == 0xdc00)) {
7251 unsigned char u1 = buffer2[utf8_written2 - 4];
7252 unsigned char u2 = buffer2[utf8_written2 - 3];
7253 unsigned char u3 = buffer2[utf8_written2 - 2];
7254 unsigned char u4 = buffer2[utf8_written2 - 1];
7255 CHECK_EQ((u1 & 0xf8), 0xf0);
7256 CHECK_EQ((u2 & 0xc0), 0x80);
7257 CHECK_EQ((u3 & 0xc0), 0x80);
7258 CHECK_EQ((u4 & 0xc0), 0x80);
7259 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7260 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7261 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7262 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7263 CHECK_EQ((u1 & 0x3), c >> 18);
7271 THREADED_TEST(Utf16) {
7272 LocalContext context;
7273 v8::HandleScope scope(context->GetIsolate());
7275 "var pad = '01234567890123456789';"
7277 "var plens = [20, 3, 3];"
7278 "p.push('01234567890123456789');"
7279 "var lead = 0xd800;"
7280 "var trail = 0xdc00;"
7281 "p.push(String.fromCharCode(0xd800));"
7282 "p.push(String.fromCharCode(0xdc00));"
7287 "for (var i = 0; i < 3; i++) {"
7288 " p[1] = String.fromCharCode(lead++);"
7289 " for (var j = 0; j < 3; j++) {"
7290 " p[2] = String.fromCharCode(trail++);"
7291 " a.push(p[i] + p[j]);"
7292 " b.push(p[i] + p[j]);"
7293 " c.push(p[i] + p[j]);"
7294 " alens.push(plens[i] + plens[j]);"
7297 "alens[5] -= 2;" // Here the surrogate pairs match up.
7302 "for (var m = 0; m < 9; m++) {"
7303 " for (var n = 0; n < 9; n++) {"
7304 " a2.push(a[m] + a[n]);"
7305 " b2.push(b[m] + b[n]);"
7306 " var newc = 'x' + c[m] + c[n] + 'y';"
7307 " c2.push(newc.substring(1, newc.length - 1));"
7308 " var utf = alens[m] + alens[n];" // And here.
7309 // The 'n's that start with 0xdc.. are 6-8
7310 // The 'm's that end with 0xd8.. are 1, 4 and 7
7311 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
7312 " a2lens.push(utf);"
7315 Utf16Helper(context, "a", "alens", 9);
7316 Utf16Helper(context, "a2", "a2lens", 81);
7317 WriteUtf8Helper(context, "b", "alens", 9);
7318 WriteUtf8Helper(context, "b2", "a2lens", 81);
7319 WriteUtf8Helper(context, "c2", "a2lens", 81);
7323 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7324 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7325 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7326 return *is1 == *is2;
7330 static void SameSymbolHelper(const char* a, const char* b) {
7331 Handle<String> symbol1 = v8::String::NewSymbol(a);
7332 Handle<String> symbol2 = v8::String::NewSymbol(b);
7333 CHECK(SameSymbol(symbol1, symbol2));
7337 THREADED_TEST(Utf16Symbol) {
7338 LocalContext context;
7339 v8::HandleScope scope(context->GetIsolate());
7341 Handle<String> symbol1 = v8::String::NewSymbol("abc");
7342 Handle<String> symbol2 = v8::String::NewSymbol("abc");
7343 CHECK(SameSymbol(symbol1, symbol2));
7345 SameSymbolHelper("\360\220\220\205", // 4 byte encoding.
7346 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
7347 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates.
7348 "\360\220\220\206"); // 4 byte encoding.
7349 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding.
7350 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
7351 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates.
7352 "x\360\220\220\206"); // 4 byte encoding.
7354 "var sym0 = 'benedictus';"
7355 "var sym0b = 'S\303\270ren';"
7356 "var sym1 = '\355\240\201\355\260\207';"
7357 "var sym2 = '\360\220\220\210';"
7358 "var sym3 = 'x\355\240\201\355\260\207';"
7359 "var sym4 = 'x\360\220\220\210';"
7360 "if (sym1.length != 2) throw sym1;"
7361 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
7362 "if (sym2.length != 2) throw sym2;"
7363 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
7364 "if (sym3.length != 3) throw sym3;"
7365 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
7366 "if (sym4.length != 3) throw sym4;"
7367 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
7368 Handle<String> sym0 = v8::String::NewSymbol("benedictus");
7369 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren");
7370 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207");
7371 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210");
7372 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207");
7373 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210");
7374 v8::Local<v8::Object> global = context->Global();
7375 Local<Value> s0 = global->Get(v8_str("sym0"));
7376 Local<Value> s0b = global->Get(v8_str("sym0b"));
7377 Local<Value> s1 = global->Get(v8_str("sym1"));
7378 Local<Value> s2 = global->Get(v8_str("sym2"));
7379 Local<Value> s3 = global->Get(v8_str("sym3"));
7380 Local<Value> s4 = global->Get(v8_str("sym4"));
7381 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
7382 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
7383 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
7384 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
7385 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
7386 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
7390 THREADED_TEST(ToArrayIndex) {
7391 LocalContext context;
7392 v8::HandleScope scope(context->GetIsolate());
7394 v8::Handle<String> str = v8_str("42");
7395 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
7396 CHECK(!index.IsEmpty());
7397 CHECK_EQ(42.0, index->Uint32Value());
7398 str = v8_str("42asdf");
7399 index = str->ToArrayIndex();
7400 CHECK(index.IsEmpty());
7401 str = v8_str("-42");
7402 index = str->ToArrayIndex();
7403 CHECK(index.IsEmpty());
7404 str = v8_str("4294967295");
7405 index = str->ToArrayIndex();
7406 CHECK(!index.IsEmpty());
7407 CHECK_EQ(4294967295.0, index->Uint32Value());
7408 v8::Handle<v8::Number> num = v8::Number::New(1);
7409 index = num->ToArrayIndex();
7410 CHECK(!index.IsEmpty());
7411 CHECK_EQ(1.0, index->Uint32Value());
7412 num = v8::Number::New(-1);
7413 index = num->ToArrayIndex();
7414 CHECK(index.IsEmpty());
7415 v8::Handle<v8::Object> obj = v8::Object::New();
7416 index = obj->ToArrayIndex();
7417 CHECK(index.IsEmpty());
7421 THREADED_TEST(ErrorConstruction) {
7422 LocalContext context;
7423 v8::HandleScope scope(context->GetIsolate());
7425 v8::Handle<String> foo = v8_str("foo");
7426 v8::Handle<String> message = v8_str("message");
7427 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
7428 CHECK(range_error->IsObject());
7429 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
7430 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
7431 CHECK(reference_error->IsObject());
7432 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
7433 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
7434 CHECK(syntax_error->IsObject());
7435 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
7436 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
7437 CHECK(type_error->IsObject());
7438 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
7439 v8::Handle<Value> error = v8::Exception::Error(foo);
7440 CHECK(error->IsObject());
7441 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7445 static void YGetter(Local<String> name,
7446 const v8::PropertyCallbackInfo<v8::Value>& info) {
7447 ApiTestFuzzer::Fuzz();
7448 info.GetReturnValue().Set(v8_num(10));
7452 static void YSetter(Local<String> name,
7454 const v8::PropertyCallbackInfo<void>& info) {
7455 if (info.This()->Has(name)) {
7456 info.This()->Delete(name);
7458 info.This()->Set(name, value);
7462 THREADED_TEST(DeleteAccessor) {
7463 v8::HandleScope scope(v8::Isolate::GetCurrent());
7464 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New();
7465 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
7466 LocalContext context;
7467 v8::Handle<v8::Object> holder = obj->NewInstance();
7468 context->Global()->Set(v8_str("holder"), holder);
7469 v8::Handle<Value> result = CompileRun(
7470 "holder.y = 11; holder.y = 12; holder.y");
7471 CHECK_EQ(12, result->Uint32Value());
7475 THREADED_TEST(TypeSwitch) {
7476 v8::HandleScope scope(v8::Isolate::GetCurrent());
7477 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New();
7478 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New();
7479 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New();
7480 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
7481 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
7482 LocalContext context;
7483 v8::Handle<v8::Object> obj0 = v8::Object::New();
7484 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
7485 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
7486 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
7487 for (int i = 0; i < 10; i++) {
7488 CHECK_EQ(0, type_switch->match(obj0));
7489 CHECK_EQ(1, type_switch->match(obj1));
7490 CHECK_EQ(2, type_switch->match(obj2));
7491 CHECK_EQ(3, type_switch->match(obj3));
7492 CHECK_EQ(3, type_switch->match(obj3));
7493 CHECK_EQ(2, type_switch->match(obj2));
7494 CHECK_EQ(1, type_switch->match(obj1));
7495 CHECK_EQ(0, type_switch->match(obj0));
7500 // For use within the TestSecurityHandler() test.
7501 static bool g_security_callback_result = false;
7502 static bool NamedSecurityTestCallback(Local<v8::Object> global,
7504 v8::AccessType type,
7505 Local<Value> data) {
7506 // Always allow read access.
7507 if (type == v8::ACCESS_GET)
7510 // Sometimes allow other access.
7511 return g_security_callback_result;
7515 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
7517 v8::AccessType type,
7518 Local<Value> data) {
7519 // Always allow read access.
7520 if (type == v8::ACCESS_GET)
7523 // Sometimes allow other access.
7524 return g_security_callback_result;
7528 static int trouble_nesting = 0;
7529 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7530 ApiTestFuzzer::Fuzz();
7533 // Call a JS function that throws an uncaught exception.
7534 Local<v8::Object> arg_this = Context::GetCurrent()->Global();
7535 Local<Value> trouble_callee = (trouble_nesting == 3) ?
7536 arg_this->Get(v8_str("trouble_callee")) :
7537 arg_this->Get(v8_str("trouble_caller"));
7538 CHECK(trouble_callee->IsFunction());
7539 args.GetReturnValue().Set(
7540 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
7544 static int report_count = 0;
7545 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
7546 v8::Handle<Value>) {
7551 // Counts uncaught exceptions, but other tests running in parallel
7552 // also have uncaught exceptions.
7553 TEST(ApiUncaughtException) {
7556 v8::HandleScope scope(env->GetIsolate());
7557 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7559 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
7560 v8::Local<v8::Object> global = env->Global();
7561 global->Set(v8_str("trouble"), fun->GetFunction());
7563 Script::Compile(v8_str("function trouble_callee() {"
7567 "function trouble_caller() {"
7570 Local<Value> trouble = global->Get(v8_str("trouble"));
7571 CHECK(trouble->IsFunction());
7572 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
7573 CHECK(trouble_callee->IsFunction());
7574 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
7575 CHECK(trouble_caller->IsFunction());
7576 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
7577 CHECK_EQ(1, report_count);
7578 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7581 static const char* script_resource_name = "ExceptionInNativeScript.js";
7582 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
7583 v8::Handle<Value>) {
7584 v8::Handle<v8::Value> name_val = message->GetScriptResourceName();
7585 CHECK(!name_val.IsEmpty() && name_val->IsString());
7586 v8::String::Utf8Value name(message->GetScriptResourceName());
7587 CHECK_EQ(script_resource_name, *name);
7588 CHECK_EQ(3, message->GetLineNumber());
7589 v8::String::Utf8Value source_line(message->GetSourceLine());
7590 CHECK_EQ(" new o.foo();", *source_line);
7594 TEST(ExceptionInNativeScript) {
7596 v8::HandleScope scope(env->GetIsolate());
7597 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
7599 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback);
7600 v8::Local<v8::Object> global = env->Global();
7601 global->Set(v8_str("trouble"), fun->GetFunction());
7603 Script::Compile(v8_str("function trouble() {\n"
7606 "};"), v8::String::New(script_resource_name))->Run();
7607 Local<Value> trouble = global->Get(v8_str("trouble"));
7608 CHECK(trouble->IsFunction());
7609 Function::Cast(*trouble)->Call(global, 0, NULL);
7610 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
7614 TEST(CompilationErrorUsingTryCatchHandler) {
7616 v8::HandleScope scope(env->GetIsolate());
7617 v8::TryCatch try_catch;
7618 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile."));
7619 CHECK_NE(NULL, *try_catch.Exception());
7620 CHECK(try_catch.HasCaught());
7624 TEST(TryCatchFinallyUsingTryCatchHandler) {
7626 v8::HandleScope scope(env->GetIsolate());
7627 v8::TryCatch try_catch;
7628 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run();
7629 CHECK(!try_catch.HasCaught());
7630 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run();
7631 CHECK(try_catch.HasCaught());
7633 Script::Compile(v8_str("(function() {"
7634 "try { throw ''; } finally { return; }"
7636 CHECK(!try_catch.HasCaught());
7637 Script::Compile(v8_str("(function()"
7638 " { try { throw ''; } finally { throw 0; }"
7640 CHECK(try_catch.HasCaught());
7644 // SecurityHandler can't be run twice
7645 TEST(SecurityHandler) {
7646 v8::HandleScope scope0(v8::Isolate::GetCurrent());
7647 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
7648 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
7649 IndexedSecurityTestCallback);
7650 // Create an environment
7651 v8::Handle<Context> context0 =
7652 Context::New(v8::Isolate::GetCurrent(), NULL, global_template);
7655 v8::Handle<v8::Object> global0 = context0->Global();
7656 v8::Handle<Script> script0 = v8_compile("foo = 111");
7658 global0->Set(v8_str("0"), v8_num(999));
7659 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
7660 CHECK_EQ(111, foo0->Int32Value());
7661 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
7662 CHECK_EQ(999, z0->Int32Value());
7664 // Create another environment, should fail security checks.
7665 v8::HandleScope scope1(v8::Isolate::GetCurrent());
7667 v8::Handle<Context> context1 =
7668 Context::New(v8::Isolate::GetCurrent(), NULL, global_template);
7671 v8::Handle<v8::Object> global1 = context1->Global();
7672 global1->Set(v8_str("othercontext"), global0);
7673 // This set will fail the security check.
7674 v8::Handle<Script> script1 =
7675 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
7677 // This read will pass the security check.
7678 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
7679 CHECK_EQ(111, foo1->Int32Value());
7680 // This read will pass the security check.
7681 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
7682 CHECK_EQ(999, z1->Int32Value());
7684 // Create another environment, should pass security checks.
7685 { g_security_callback_result = true; // allow security handler to pass.
7686 v8::HandleScope scope2(v8::Isolate::GetCurrent());
7687 LocalContext context2;
7688 v8::Handle<v8::Object> global2 = context2->Global();
7689 global2->Set(v8_str("othercontext"), global0);
7690 v8::Handle<Script> script2 =
7691 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
7693 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
7694 CHECK_EQ(333, foo2->Int32Value());
7695 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
7696 CHECK_EQ(888, z2->Int32Value());
7704 THREADED_TEST(SecurityChecks) {
7706 v8::HandleScope handle_scope(env1->GetIsolate());
7707 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7709 Local<Value> foo = v8_str("foo");
7710 Local<Value> bar = v8_str("bar");
7712 // Set to the same domain.
7713 env1->SetSecurityToken(foo);
7715 // Create a function in env1.
7716 Script::Compile(v8_str("spy=function(){return spy;}"))->Run();
7717 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
7718 CHECK(spy->IsFunction());
7720 // Create another function accessing global objects.
7721 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run();
7722 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
7723 CHECK(spy2->IsFunction());
7725 // Switch to env2 in the same domain and invoke spy on env2.
7727 env2->SetSecurityToken(foo);
7729 Context::Scope scope_env2(env2);
7730 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
7731 CHECK(result->IsFunction());
7735 env2->SetSecurityToken(bar);
7736 Context::Scope scope_env2(env2);
7738 // Call cross_domain_call, it should throw an exception
7739 v8::TryCatch try_catch;
7740 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
7741 CHECK(try_catch.HasCaught());
7746 // Regression test case for issue 1183439.
7747 THREADED_TEST(SecurityChecksForPrototypeChain) {
7748 LocalContext current;
7749 v8::HandleScope scope(current->GetIsolate());
7750 v8::Handle<Context> other = Context::New(current->GetIsolate());
7752 // Change context to be able to get to the Object function in the
7753 // other context without hitting the security checks.
7754 v8::Local<Value> other_object;
7755 { Context::Scope scope(other);
7756 other_object = other->Global()->Get(v8_str("Object"));
7757 other->Global()->Set(v8_num(42), v8_num(87));
7760 current->Global()->Set(v8_str("other"), other->Global());
7761 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
7763 // Make sure the security check fails here and we get an undefined
7764 // result instead of getting the Object function. Repeat in a loop
7765 // to make sure to exercise the IC code.
7766 v8::Local<Script> access_other0 = v8_compile("other.Object");
7767 v8::Local<Script> access_other1 = v8_compile("other[42]");
7768 for (int i = 0; i < 5; i++) {
7769 CHECK(!access_other0->Run()->Equals(other_object));
7770 CHECK(access_other0->Run()->IsUndefined());
7771 CHECK(!access_other1->Run()->Equals(v8_num(87)));
7772 CHECK(access_other1->Run()->IsUndefined());
7775 // Create an object that has 'other' in its prototype chain and make
7776 // sure we cannot access the Object function indirectly through
7777 // that. Repeat in a loop to make sure to exercise the IC code.
7778 v8_compile("function F() { };"
7779 "F.prototype = other;"
7780 "var f = new F();")->Run();
7781 v8::Local<Script> access_f0 = v8_compile("f.Object");
7782 v8::Local<Script> access_f1 = v8_compile("f[42]");
7783 for (int j = 0; j < 5; j++) {
7784 CHECK(!access_f0->Run()->Equals(other_object));
7785 CHECK(access_f0->Run()->IsUndefined());
7786 CHECK(!access_f1->Run()->Equals(v8_num(87)));
7787 CHECK(access_f1->Run()->IsUndefined());
7790 // Now it gets hairy: Set the prototype for the other global object
7791 // to be the current global object. The prototype chain for 'f' now
7792 // goes through 'other' but ends up in the current global object.
7793 { Context::Scope scope(other);
7794 other->Global()->Set(v8_str("__proto__"), current->Global());
7796 // Set a named and an index property on the current global
7797 // object. To force the lookup to go through the other global object,
7798 // the properties must not exist in the other global object.
7799 current->Global()->Set(v8_str("foo"), v8_num(100));
7800 current->Global()->Set(v8_num(99), v8_num(101));
7801 // Try to read the properties from f and make sure that the access
7802 // gets stopped by the security checks on the other global object.
7803 Local<Script> access_f2 = v8_compile("f.foo");
7804 Local<Script> access_f3 = v8_compile("f[99]");
7805 for (int k = 0; k < 5; k++) {
7806 CHECK(!access_f2->Run()->Equals(v8_num(100)));
7807 CHECK(access_f2->Run()->IsUndefined());
7808 CHECK(!access_f3->Run()->Equals(v8_num(101)));
7809 CHECK(access_f3->Run()->IsUndefined());
7814 THREADED_TEST(CrossDomainDelete) {
7816 v8::HandleScope handle_scope(env1->GetIsolate());
7817 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7819 Local<Value> foo = v8_str("foo");
7820 Local<Value> bar = v8_str("bar");
7822 // Set to the same domain.
7823 env1->SetSecurityToken(foo);
7824 env2->SetSecurityToken(foo);
7826 env1->Global()->Set(v8_str("prop"), v8_num(3));
7827 env2->Global()->Set(v8_str("env1"), env1->Global());
7829 // Change env2 to a different domain and delete env1.prop.
7830 env2->SetSecurityToken(bar);
7832 Context::Scope scope_env2(env2);
7833 Local<Value> result =
7834 Script::Compile(v8_str("delete env1.prop"))->Run();
7835 CHECK(result->IsFalse());
7838 // Check that env1.prop still exists.
7839 Local<Value> v = env1->Global()->Get(v8_str("prop"));
7840 CHECK(v->IsNumber());
7841 CHECK_EQ(3, v->Int32Value());
7845 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
7847 v8::HandleScope handle_scope(env1->GetIsolate());
7848 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7850 Local<Value> foo = v8_str("foo");
7851 Local<Value> bar = v8_str("bar");
7853 // Set to the same domain.
7854 env1->SetSecurityToken(foo);
7855 env2->SetSecurityToken(foo);
7857 env1->Global()->Set(v8_str("prop"), v8_num(3));
7858 env2->Global()->Set(v8_str("env1"), env1->Global());
7860 // env1.prop is enumerable in env2.
7861 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
7863 Context::Scope scope_env2(env2);
7864 Local<Value> result = Script::Compile(test)->Run();
7865 CHECK(result->IsTrue());
7868 // Change env2 to a different domain and test again.
7869 env2->SetSecurityToken(bar);
7871 Context::Scope scope_env2(env2);
7872 Local<Value> result = Script::Compile(test)->Run();
7873 CHECK(result->IsFalse());
7878 THREADED_TEST(CrossDomainForIn) {
7880 v8::HandleScope handle_scope(env1->GetIsolate());
7881 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7883 Local<Value> foo = v8_str("foo");
7884 Local<Value> bar = v8_str("bar");
7886 // Set to the same domain.
7887 env1->SetSecurityToken(foo);
7888 env2->SetSecurityToken(foo);
7890 env1->Global()->Set(v8_str("prop"), v8_num(3));
7891 env2->Global()->Set(v8_str("env1"), env1->Global());
7893 // Change env2 to a different domain and set env1's global object
7894 // as the __proto__ of an object in env2 and enumerate properties
7895 // in for-in. It shouldn't enumerate properties on env1's global
7897 env2->SetSecurityToken(bar);
7899 Context::Scope scope_env2(env2);
7900 Local<Value> result =
7901 CompileRun("(function(){var obj = {'__proto__':env1};"
7902 "for (var p in obj)"
7903 " if (p == 'prop') return false;"
7904 "return true;})()");
7905 CHECK(result->IsTrue());
7910 TEST(ContextDetachGlobal) {
7912 v8::HandleScope handle_scope(env1->GetIsolate());
7913 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7915 Local<v8::Object> global1 = env1->Global();
7917 Local<Value> foo = v8_str("foo");
7919 // Set to the same domain.
7920 env1->SetSecurityToken(foo);
7921 env2->SetSecurityToken(foo);
7926 // Create a function in env2 and add a reference to it in env1.
7927 Local<v8::Object> global2 = env2->Global();
7928 global2->Set(v8_str("prop"), v8::Integer::New(1));
7929 CompileRun("function getProp() {return prop;}");
7931 env1->Global()->Set(v8_str("getProp"),
7932 global2->Get(v8_str("getProp")));
7934 // Detach env2's global, and reuse the global object of env2
7936 env2->DetachGlobal();
7937 // env2 has a new global object.
7938 CHECK(!env2->Global()->Equals(global2));
7940 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
7942 v8::Handle<v8::ObjectTemplate>(),
7944 env3->SetSecurityToken(v8_str("bar"));
7947 Local<v8::Object> global3 = env3->Global();
7948 CHECK_EQ(global2, global3);
7949 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
7950 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
7951 global3->Set(v8_str("prop"), v8::Integer::New(-1));
7952 global3->Set(v8_str("prop2"), v8::Integer::New(2));
7955 // Call getProp in env1, and it should return the value 1
7957 Local<Value> get_prop = global1->Get(v8_str("getProp"));
7958 CHECK(get_prop->IsFunction());
7959 v8::TryCatch try_catch;
7960 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
7961 CHECK(!try_catch.HasCaught());
7962 CHECK_EQ(1, r->Int32Value());
7965 // Check that env3 is not accessible from env1
7967 Local<Value> r = global3->Get(v8_str("prop2"));
7968 CHECK(r->IsUndefined());
7973 TEST(DetachAndReattachGlobal) {
7975 v8::HandleScope scope(env1->GetIsolate());
7977 // Create second environment.
7978 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7980 Local<Value> foo = v8_str("foo");
7982 // Set same security token for env1 and env2.
7983 env1->SetSecurityToken(foo);
7984 env2->SetSecurityToken(foo);
7986 // Create a property on the global object in env2.
7988 v8::Context::Scope scope(env2);
7989 env2->Global()->Set(v8_str("p"), v8::Integer::New(42));
7992 // Create a reference to env2 global from env1 global.
7993 env1->Global()->Set(v8_str("other"), env2->Global());
7995 // Check that we have access to other.p in env2 from env1.
7996 Local<Value> result = CompileRun("other.p");
7997 CHECK(result->IsInt32());
7998 CHECK_EQ(42, result->Int32Value());
8000 // Hold on to global from env2 and detach global from env2.
8001 Local<v8::Object> global2 = env2->Global();
8002 env2->DetachGlobal();
8004 // Check that the global has been detached. No other.p property can
8006 result = CompileRun("other.p");
8007 CHECK(result->IsUndefined());
8009 // Reuse global2 for env3.
8010 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8012 v8::Handle<v8::ObjectTemplate>(),
8014 CHECK_EQ(global2, env3->Global());
8016 // Start by using the same security token for env3 as for env1 and env2.
8017 env3->SetSecurityToken(foo);
8019 // Create a property on the global object in env3.
8021 v8::Context::Scope scope(env3);
8022 env3->Global()->Set(v8_str("p"), v8::Integer::New(24));
8025 // Check that other.p is now the property in env3 and that we have access.
8026 result = CompileRun("other.p");
8027 CHECK(result->IsInt32());
8028 CHECK_EQ(24, result->Int32Value());
8030 // Change security token for env3 to something different from env1 and env2.
8031 env3->SetSecurityToken(v8_str("bar"));
8033 // Check that we do not have access to other.p in env1. |other| is now
8034 // the global object for env3 which has a different security token,
8035 // so access should be blocked.
8036 result = CompileRun("other.p");
8037 CHECK(result->IsUndefined());
8039 // Detach the global for env3 and reattach it to env2.
8040 env3->DetachGlobal();
8041 env2->ReattachGlobal(global2);
8043 // Check that we have access to other.p again in env1. |other| is now
8044 // the global object for env2 which has the same security token as env1.
8045 result = CompileRun("other.p");
8046 CHECK(result->IsInt32());
8047 CHECK_EQ(42, result->Int32Value());
8051 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8052 static bool NamedAccessBlocker(Local<v8::Object> global,
8054 v8::AccessType type,
8055 Local<Value> data) {
8056 return Context::GetCurrent()->Global()->Equals(global) ||
8057 allowed_access_type[type];
8061 static bool IndexedAccessBlocker(Local<v8::Object> global,
8063 v8::AccessType type,
8064 Local<Value> data) {
8065 return Context::GetCurrent()->Global()->Equals(global) ||
8066 allowed_access_type[type];
8070 static int g_echo_value = -1;
8071 static void EchoGetter(
8073 const v8::PropertyCallbackInfo<v8::Value>& info) {
8074 info.GetReturnValue().Set(v8_num(g_echo_value));
8078 static void EchoSetter(Local<String> name,
8080 const v8::PropertyCallbackInfo<void>&) {
8081 if (value->IsNumber())
8082 g_echo_value = value->Int32Value();
8086 static void UnreachableGetter(
8088 const v8::PropertyCallbackInfo<v8::Value>& info) {
8089 CHECK(false); // This function should not be called..
8093 static void UnreachableSetter(Local<String>,
8095 const v8::PropertyCallbackInfo<void>&) {
8096 CHECK(false); // This function should nto be called.
8100 TEST(AccessControl) {
8101 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8102 v8::HandleScope handle_scope(isolate);
8103 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8105 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8106 IndexedAccessBlocker);
8108 // Add an accessor accessible by cross-domain JS code.
8109 global_template->SetAccessor(
8110 v8_str("accessible_prop"),
8111 EchoGetter, EchoSetter,
8112 v8::Handle<Value>(),
8113 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8115 // Add an accessor that is not accessible by cross-domain JS code.
8116 global_template->SetAccessor(v8_str("blocked_prop"),
8117 UnreachableGetter, UnreachableSetter,
8118 v8::Handle<Value>(),
8121 // Create an environment
8122 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8125 v8::Handle<v8::Object> global0 = context0->Global();
8127 // Define a property with JS getter and setter.
8129 "function getter() { return 'getter'; };\n"
8130 "function setter() { return 'setter'; }\n"
8131 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8133 Local<Value> getter = global0->Get(v8_str("getter"));
8134 Local<Value> setter = global0->Get(v8_str("setter"));
8136 // And define normal element.
8137 global0->Set(239, v8_str("239"));
8139 // Define an element with JS getter and setter.
8141 "function el_getter() { return 'el_getter'; };\n"
8142 "function el_setter() { return 'el_setter'; };\n"
8143 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8145 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8146 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8148 v8::HandleScope scope1(isolate);
8150 v8::Local<Context> context1 = Context::New(isolate);
8153 v8::Handle<v8::Object> global1 = context1->Global();
8154 global1->Set(v8_str("other"), global0);
8156 // Access blocked property.
8157 CompileRun("other.blocked_prop = 1");
8159 ExpectUndefined("other.blocked_prop");
8161 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8162 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')");
8164 // Enable ACCESS_HAS
8165 allowed_access_type[v8::ACCESS_HAS] = true;
8166 ExpectUndefined("other.blocked_prop");
8167 // ... and now we can get the descriptor...
8169 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value");
8170 // ... and enumerate the property.
8171 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')");
8172 allowed_access_type[v8::ACCESS_HAS] = false;
8174 // Access blocked element.
8175 CompileRun("other[239] = 1");
8177 ExpectUndefined("other[239]");
8178 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')");
8179 ExpectFalse("propertyIsEnumerable.call(other, '239')");
8181 // Enable ACCESS_HAS
8182 allowed_access_type[v8::ACCESS_HAS] = true;
8183 ExpectUndefined("other[239]");
8184 // ... and now we can get the descriptor...
8185 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value");
8186 // ... and enumerate the property.
8187 ExpectTrue("propertyIsEnumerable.call(other, '239')");
8188 allowed_access_type[v8::ACCESS_HAS] = false;
8190 // Access a property with JS accessor.
8191 CompileRun("other.js_accessor_p = 2");
8193 ExpectUndefined("other.js_accessor_p");
8195 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')");
8197 // Enable ACCESS_HAS.
8198 allowed_access_type[v8::ACCESS_HAS] = true;
8199 ExpectUndefined("other.js_accessor_p");
8201 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
8203 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
8205 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8206 allowed_access_type[v8::ACCESS_HAS] = false;
8208 // Enable both ACCESS_HAS and ACCESS_GET.
8209 allowed_access_type[v8::ACCESS_HAS] = true;
8210 allowed_access_type[v8::ACCESS_GET] = true;
8212 ExpectString("other.js_accessor_p", "getter");
8214 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8216 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set");
8218 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8220 allowed_access_type[v8::ACCESS_GET] = false;
8221 allowed_access_type[v8::ACCESS_HAS] = false;
8223 // Enable both ACCESS_HAS and ACCESS_SET.
8224 allowed_access_type[v8::ACCESS_HAS] = true;
8225 allowed_access_type[v8::ACCESS_SET] = true;
8227 ExpectUndefined("other.js_accessor_p");
8229 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get");
8231 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8233 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8235 allowed_access_type[v8::ACCESS_SET] = false;
8236 allowed_access_type[v8::ACCESS_HAS] = false;
8238 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
8239 allowed_access_type[v8::ACCESS_HAS] = true;
8240 allowed_access_type[v8::ACCESS_GET] = true;
8241 allowed_access_type[v8::ACCESS_SET] = true;
8243 ExpectString("other.js_accessor_p", "getter");
8245 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8247 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8249 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8251 allowed_access_type[v8::ACCESS_SET] = false;
8252 allowed_access_type[v8::ACCESS_GET] = false;
8253 allowed_access_type[v8::ACCESS_HAS] = false;
8255 // Access an element with JS accessor.
8256 CompileRun("other[42] = 2");
8258 ExpectUndefined("other[42]");
8259 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')");
8261 // Enable ACCESS_HAS.
8262 allowed_access_type[v8::ACCESS_HAS] = true;
8263 ExpectUndefined("other[42]");
8264 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
8265 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
8266 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8267 allowed_access_type[v8::ACCESS_HAS] = false;
8269 // Enable both ACCESS_HAS and ACCESS_GET.
8270 allowed_access_type[v8::ACCESS_HAS] = true;
8271 allowed_access_type[v8::ACCESS_GET] = true;
8273 ExpectString("other[42]", "el_getter");
8274 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8275 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set");
8276 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8278 allowed_access_type[v8::ACCESS_GET] = false;
8279 allowed_access_type[v8::ACCESS_HAS] = false;
8281 // Enable both ACCESS_HAS and ACCESS_SET.
8282 allowed_access_type[v8::ACCESS_HAS] = true;
8283 allowed_access_type[v8::ACCESS_SET] = true;
8285 ExpectUndefined("other[42]");
8286 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get");
8287 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8288 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8290 allowed_access_type[v8::ACCESS_SET] = false;
8291 allowed_access_type[v8::ACCESS_HAS] = false;
8293 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET.
8294 allowed_access_type[v8::ACCESS_HAS] = true;
8295 allowed_access_type[v8::ACCESS_GET] = true;
8296 allowed_access_type[v8::ACCESS_SET] = true;
8298 ExpectString("other[42]", "el_getter");
8299 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8300 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8301 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8303 allowed_access_type[v8::ACCESS_SET] = false;
8304 allowed_access_type[v8::ACCESS_GET] = false;
8305 allowed_access_type[v8::ACCESS_HAS] = false;
8307 v8::Handle<Value> value;
8309 // Access accessible property
8310 value = CompileRun("other.accessible_prop = 3");
8311 CHECK(value->IsNumber());
8312 CHECK_EQ(3, value->Int32Value());
8313 CHECK_EQ(3, g_echo_value);
8315 value = CompileRun("other.accessible_prop");
8316 CHECK(value->IsNumber());
8317 CHECK_EQ(3, value->Int32Value());
8320 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
8321 CHECK(value->IsNumber());
8322 CHECK_EQ(3, value->Int32Value());
8324 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
8325 CHECK(value->IsTrue());
8327 // Enumeration doesn't enumerate accessors from inaccessible objects in
8328 // the prototype chain even if the accessors are in themselves accessible.
8330 CompileRun("(function(){var obj = {'__proto__':other};"
8331 "for (var p in obj)"
8332 " if (p == 'accessible_prop' || p == 'blocked_prop') {"
8335 "return true;})()");
8336 CHECK(value->IsTrue());
8343 TEST(AccessControlES5) {
8344 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8345 v8::HandleScope handle_scope(isolate);
8346 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
8348 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8349 IndexedAccessBlocker);
8351 // Add accessible accessor.
8352 global_template->SetAccessor(
8353 v8_str("accessible_prop"),
8354 EchoGetter, EchoSetter,
8355 v8::Handle<Value>(),
8356 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8359 // Add an accessor that is not accessible by cross-domain JS code.
8360 global_template->SetAccessor(v8_str("blocked_prop"),
8361 UnreachableGetter, UnreachableSetter,
8362 v8::Handle<Value>(),
8365 // Create an environment
8366 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8369 v8::Handle<v8::Object> global0 = context0->Global();
8371 v8::Local<Context> context1 = Context::New(isolate);
8373 v8::Handle<v8::Object> global1 = context1->Global();
8374 global1->Set(v8_str("other"), global0);
8376 // Regression test for issue 1154.
8377 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1");
8379 ExpectUndefined("other.blocked_prop");
8381 // Regression test for issue 1027.
8382 CompileRun("Object.defineProperty(\n"
8383 " other, 'blocked_prop', {configurable: false})");
8384 ExpectUndefined("other.blocked_prop");
8386 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')");
8388 // Regression test for issue 1171.
8389 ExpectTrue("Object.isExtensible(other)");
8390 CompileRun("Object.preventExtensions(other)");
8391 ExpectTrue("Object.isExtensible(other)");
8393 // Object.seal and Object.freeze.
8394 CompileRun("Object.freeze(other)");
8395 ExpectTrue("Object.isExtensible(other)");
8397 CompileRun("Object.seal(other)");
8398 ExpectTrue("Object.isExtensible(other)");
8400 // Regression test for issue 1250.
8401 // Make sure that we can set the accessible accessors value using normal
8403 CompileRun("other.accessible_prop = 42");
8404 CHECK_EQ(42, g_echo_value);
8406 v8::Handle<Value> value;
8407 // We follow Safari in ignoring assignments to host object accessors.
8408 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
8409 value = CompileRun("other.accessible_prop == 42");
8410 CHECK(value->IsTrue());
8414 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global,
8416 v8::AccessType type,
8417 Local<Value> data) {
8422 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global,
8424 v8::AccessType type,
8425 Local<Value> data) {
8430 THREADED_TEST(AccessControlGetOwnPropertyNames) {
8431 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8432 v8::HandleScope handle_scope(isolate);
8433 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
8435 obj_template->Set(v8_str("x"), v8::Integer::New(42));
8436 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker,
8437 GetOwnPropertyNamesIndexedBlocker);
8439 // Create an environment
8440 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
8443 v8::Handle<v8::Object> global0 = context0->Global();
8445 v8::HandleScope scope1(v8::Isolate::GetCurrent());
8447 v8::Local<Context> context1 = Context::New(isolate);
8450 v8::Handle<v8::Object> global1 = context1->Global();
8451 global1->Set(v8_str("other"), global0);
8452 global1->Set(v8_str("object"), obj_template->NewInstance());
8454 v8::Handle<Value> value;
8456 // Attempt to get the property names of the other global object and
8457 // of an object that requires access checks. Accessing the other
8458 // global object should be blocked by access checks on the global
8459 // proxy object. Accessing the object that requires access checks
8460 // is blocked by the access checks on the object itself.
8461 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
8462 CHECK(value->IsTrue());
8464 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
8465 CHECK(value->IsTrue());
8472 static void IndexedPropertyEnumerator(
8473 const v8::PropertyCallbackInfo<v8::Array>& info) {
8474 v8::Handle<v8::Array> result = v8::Array::New(2);
8475 result->Set(0, v8::Integer::New(7));
8476 result->Set(1, v8::Object::New());
8477 info.GetReturnValue().Set(result);
8481 static void NamedPropertyEnumerator(
8482 const v8::PropertyCallbackInfo<v8::Array>& info) {
8483 v8::Handle<v8::Array> result = v8::Array::New(2);
8484 result->Set(0, v8_str("x"));
8485 result->Set(1, v8::Object::New());
8486 info.GetReturnValue().Set(result);
8490 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
8491 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
8492 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New();
8494 obj_template->Set(v8_str("7"), v8::Integer::New(7));
8495 obj_template->Set(v8_str("x"), v8::Integer::New(42));
8496 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
8497 IndexedPropertyEnumerator);
8498 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
8499 NamedPropertyEnumerator);
8501 LocalContext context;
8502 v8::Handle<v8::Object> global = context->Global();
8503 global->Set(v8_str("object"), obj_template->NewInstance());
8505 v8::Handle<v8::Value> result =
8506 CompileRun("Object.getOwnPropertyNames(object)");
8507 CHECK(result->IsArray());
8508 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
8509 CHECK_EQ(3, result_array->Length());
8510 CHECK(result_array->Get(0)->IsString());
8511 CHECK(result_array->Get(1)->IsString());
8512 CHECK(result_array->Get(2)->IsString());
8513 CHECK_EQ(v8_str("7"), result_array->Get(0));
8514 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
8515 CHECK_EQ(v8_str("x"), result_array->Get(2));
8519 static void ConstTenGetter(Local<String> name,
8520 const v8::PropertyCallbackInfo<v8::Value>& info) {
8521 info.GetReturnValue().Set(v8_num(10));
8525 THREADED_TEST(CrossDomainAccessors) {
8526 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8527 v8::HandleScope handle_scope(isolate);
8529 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New();
8531 v8::Handle<v8::ObjectTemplate> global_template =
8532 func_template->InstanceTemplate();
8534 v8::Handle<v8::ObjectTemplate> proto_template =
8535 func_template->PrototypeTemplate();
8537 // Add an accessor to proto that's accessible by cross-domain JS code.
8538 proto_template->SetAccessor(v8_str("accessible"),
8540 v8::Handle<Value>(),
8543 // Add an accessor that is not accessible by cross-domain JS code.
8544 global_template->SetAccessor(v8_str("unreachable"),
8545 UnreachableGetter, 0,
8546 v8::Handle<Value>(),
8549 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8552 Local<v8::Object> global = context0->Global();
8553 // Add a normal property that shadows 'accessible'
8554 global->Set(v8_str("accessible"), v8_num(11));
8556 // Enter a new context.
8557 v8::HandleScope scope1(v8::Isolate::GetCurrent());
8558 v8::Local<Context> context1 = Context::New(isolate);
8561 v8::Handle<v8::Object> global1 = context1->Global();
8562 global1->Set(v8_str("other"), global);
8564 // Should return 10, instead of 11
8565 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
8566 CHECK(value->IsNumber());
8567 CHECK_EQ(10, value->Int32Value());
8569 value = v8_compile("other.unreachable")->Run();
8570 CHECK(value->IsUndefined());
8577 static int named_access_count = 0;
8578 static int indexed_access_count = 0;
8580 static bool NamedAccessCounter(Local<v8::Object> global,
8582 v8::AccessType type,
8583 Local<Value> data) {
8584 named_access_count++;
8589 static bool IndexedAccessCounter(Local<v8::Object> global,
8591 v8::AccessType type,
8592 Local<Value> data) {
8593 indexed_access_count++;
8598 // This one is too easily disturbed by other tests.
8599 TEST(AccessControlIC) {
8600 named_access_count = 0;
8601 indexed_access_count = 0;
8603 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8604 v8::HandleScope handle_scope(isolate);
8606 // Create an environment.
8607 v8::Local<Context> context0 = Context::New(isolate);
8610 // Create an object that requires access-check functions to be
8611 // called for cross-domain access.
8612 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
8613 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
8614 IndexedAccessCounter);
8615 Local<v8::Object> object = object_template->NewInstance();
8617 v8::HandleScope scope1(isolate);
8619 // Create another environment.
8620 v8::Local<Context> context1 = Context::New(isolate);
8623 // Make easy access to the object from the other environment.
8624 v8::Handle<v8::Object> global1 = context1->Global();
8625 global1->Set(v8_str("obj"), object);
8627 v8::Handle<Value> value;
8629 // Check that the named access-control function is called every time.
8630 CompileRun("function testProp(obj) {"
8631 " for (var i = 0; i < 10; i++) obj.prop = 1;"
8632 " for (var j = 0; j < 10; j++) obj.prop;"
8635 value = CompileRun("testProp(obj)");
8636 CHECK(value->IsNumber());
8637 CHECK_EQ(1, value->Int32Value());
8638 CHECK_EQ(21, named_access_count);
8640 // Check that the named access-control function is called every time.
8641 CompileRun("var p = 'prop';"
8642 "function testKeyed(obj) {"
8643 " for (var i = 0; i < 10; i++) obj[p] = 1;"
8644 " for (var j = 0; j < 10; j++) obj[p];"
8647 // Use obj which requires access checks. No inline caching is used
8649 value = CompileRun("testKeyed(obj)");
8650 CHECK(value->IsNumber());
8651 CHECK_EQ(1, value->Int32Value());
8652 CHECK_EQ(42, named_access_count);
8653 // Force the inline caches into generic state and try again.
8654 CompileRun("testKeyed({ a: 0 })");
8655 CompileRun("testKeyed({ b: 0 })");
8656 value = CompileRun("testKeyed(obj)");
8657 CHECK(value->IsNumber());
8658 CHECK_EQ(1, value->Int32Value());
8659 CHECK_EQ(63, named_access_count);
8661 // Check that the indexed access-control function is called every time.
8662 CompileRun("function testIndexed(obj) {"
8663 " for (var i = 0; i < 10; i++) obj[0] = 1;"
8664 " for (var j = 0; j < 10; j++) obj[0];"
8667 value = CompileRun("testIndexed(obj)");
8668 CHECK(value->IsNumber());
8669 CHECK_EQ(1, value->Int32Value());
8670 CHECK_EQ(21, indexed_access_count);
8671 // Force the inline caches into generic state.
8672 CompileRun("testIndexed(new Array(1))");
8673 // Test that the indexed access check is called.
8674 value = CompileRun("testIndexed(obj)");
8675 CHECK(value->IsNumber());
8676 CHECK_EQ(1, value->Int32Value());
8677 CHECK_EQ(42, indexed_access_count);
8679 // Check that the named access check is called when invoking
8680 // functions on an object that requires access checks.
8681 CompileRun("obj.f = function() {}");
8682 CompileRun("function testCallNormal(obj) {"
8683 " for (var i = 0; i < 10; i++) obj.f();"
8685 CompileRun("testCallNormal(obj)");
8686 CHECK_EQ(74, named_access_count);
8688 // Force obj into slow case.
8689 value = CompileRun("delete obj.prop");
8690 CHECK(value->BooleanValue());
8691 // Force inline caches into dictionary probing mode.
8692 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
8693 // Test that the named access check is called.
8694 value = CompileRun("testProp(obj);");
8695 CHECK(value->IsNumber());
8696 CHECK_EQ(1, value->Int32Value());
8697 CHECK_EQ(96, named_access_count);
8699 // Force the call inline cache into dictionary probing mode.
8700 CompileRun("o.f = function() {}; testCallNormal(o)");
8701 // Test that the named access check is still called for each
8702 // invocation of the function.
8703 value = CompileRun("testCallNormal(obj)");
8704 CHECK_EQ(106, named_access_count);
8711 static bool NamedAccessFlatten(Local<v8::Object> global,
8713 v8::AccessType type,
8714 Local<Value> data) {
8718 CHECK(name->IsString());
8720 memset(buf, 0x1, sizeof(buf));
8721 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8726 memset(buf, 0x1, sizeof(buf));
8727 len = name.As<String>()->Write(buf2);
8734 static bool IndexedAccessFlatten(Local<v8::Object> global,
8736 v8::AccessType type,
8737 Local<Value> data) {
8742 // Regression test. In access checks, operations that may cause
8743 // garbage collection are not allowed. It used to be the case that
8744 // using the Write operation on a string could cause a garbage
8745 // collection due to flattening of the string. This is no longer the
8747 THREADED_TEST(AccessControlFlatten) {
8748 named_access_count = 0;
8749 indexed_access_count = 0;
8751 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8752 v8::HandleScope handle_scope(isolate);
8754 // Create an environment.
8755 v8::Local<Context> context0 = Context::New(isolate);
8758 // Create an object that requires access-check functions to be
8759 // called for cross-domain access.
8760 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
8761 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
8762 IndexedAccessFlatten);
8763 Local<v8::Object> object = object_template->NewInstance();
8765 v8::HandleScope scope1(isolate);
8767 // Create another environment.
8768 v8::Local<Context> context1 = Context::New(isolate);
8771 // Make easy access to the object from the other environment.
8772 v8::Handle<v8::Object> global1 = context1->Global();
8773 global1->Set(v8_str("obj"), object);
8775 v8::Handle<Value> value;
8777 value = v8_compile("var p = 'as' + 'df';")->Run();
8778 value = v8_compile("obj[p];")->Run();
8785 static void AccessControlNamedGetter(
8787 const v8::PropertyCallbackInfo<v8::Value>& info) {
8788 info.GetReturnValue().Set(42);
8792 static void AccessControlNamedSetter(
8795 const v8::PropertyCallbackInfo<v8::Value>& info) {
8796 info.GetReturnValue().Set(value);
8800 static void AccessControlIndexedGetter(
8802 const v8::PropertyCallbackInfo<v8::Value>& info) {
8803 info.GetReturnValue().Set(v8_num(42));
8807 static void AccessControlIndexedSetter(
8810 const v8::PropertyCallbackInfo<v8::Value>& info) {
8811 info.GetReturnValue().Set(value);
8815 THREADED_TEST(AccessControlInterceptorIC) {
8816 named_access_count = 0;
8817 indexed_access_count = 0;
8819 v8::Isolate* isolate = v8::Isolate::GetCurrent();
8820 v8::HandleScope handle_scope(isolate);
8822 // Create an environment.
8823 v8::Local<Context> context0 = Context::New(isolate);
8826 // Create an object that requires access-check functions to be
8827 // called for cross-domain access. The object also has interceptors
8829 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
8830 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
8831 IndexedAccessCounter);
8832 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
8833 AccessControlNamedSetter);
8834 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
8835 AccessControlIndexedSetter);
8836 Local<v8::Object> object = object_template->NewInstance();
8838 v8::HandleScope scope1(isolate);
8840 // Create another environment.
8841 v8::Local<Context> context1 = Context::New(isolate);
8844 // Make easy access to the object from the other environment.
8845 v8::Handle<v8::Object> global1 = context1->Global();
8846 global1->Set(v8_str("obj"), object);
8848 v8::Handle<Value> value;
8850 // Check that the named access-control function is called every time
8851 // eventhough there is an interceptor on the object.
8852 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
8853 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
8855 CHECK(value->IsNumber());
8856 CHECK_EQ(42, value->Int32Value());
8857 CHECK_EQ(21, named_access_count);
8859 value = v8_compile("var p = 'x';")->Run();
8860 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
8861 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
8863 CHECK(value->IsNumber());
8864 CHECK_EQ(42, value->Int32Value());
8865 CHECK_EQ(42, named_access_count);
8867 // Check that the indexed access-control function is called every
8868 // time eventhough there is an interceptor on the object.
8869 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
8870 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
8872 CHECK(value->IsNumber());
8873 CHECK_EQ(42, value->Int32Value());
8874 CHECK_EQ(21, indexed_access_count);
8881 THREADED_TEST(Version) {
8882 v8::V8::GetVersion();
8886 static void InstanceFunctionCallback(
8887 const v8::FunctionCallbackInfo<v8::Value>& args) {
8888 ApiTestFuzzer::Fuzz();
8889 args.GetReturnValue().Set(v8_num(12));
8893 THREADED_TEST(InstanceProperties) {
8894 LocalContext context;
8895 v8::HandleScope handle_scope(context->GetIsolate());
8897 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8898 Local<ObjectTemplate> instance = t->InstanceTemplate();
8900 instance->Set(v8_str("x"), v8_num(42));
8901 instance->Set(v8_str("f"),
8902 v8::FunctionTemplate::New(InstanceFunctionCallback));
8904 Local<Value> o = t->GetFunction()->NewInstance();
8906 context->Global()->Set(v8_str("i"), o);
8907 Local<Value> value = Script::Compile(v8_str("i.x"))->Run();
8908 CHECK_EQ(42, value->Int32Value());
8910 value = Script::Compile(v8_str("i.f()"))->Run();
8911 CHECK_EQ(12, value->Int32Value());
8915 static void GlobalObjectInstancePropertiesGet(
8917 const v8::PropertyCallbackInfo<v8::Value>&) {
8918 ApiTestFuzzer::Fuzz();
8922 THREADED_TEST(GlobalObjectInstanceProperties) {
8923 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
8925 Local<Value> global_object;
8927 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8928 t->InstanceTemplate()->SetNamedPropertyHandler(
8929 GlobalObjectInstancePropertiesGet);
8930 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8931 instance_template->Set(v8_str("x"), v8_num(42));
8932 instance_template->Set(v8_str("f"),
8933 v8::FunctionTemplate::New(InstanceFunctionCallback));
8935 // The script to check how Crankshaft compiles missing global function
8936 // invocations. function g is not defined and should throw on call.
8937 const char* script =
8938 "function wrapper(call) {"
8939 " var x = 0, y = 1;"
8940 " for (var i = 0; i < 1000; i++) {"
8946 "for (var i = 0; i < 17; i++) wrapper(false);"
8948 "try { wrapper(true); } catch (e) { thrown = 1; };"
8952 LocalContext env(NULL, instance_template);
8953 // Hold on to the global object so it can be used again in another
8954 // environment initialization.
8955 global_object = env->Global();
8957 Local<Value> value = Script::Compile(v8_str("x"))->Run();
8958 CHECK_EQ(42, value->Int32Value());
8959 value = Script::Compile(v8_str("f()"))->Run();
8960 CHECK_EQ(12, value->Int32Value());
8961 value = Script::Compile(v8_str(script))->Run();
8962 CHECK_EQ(1, value->Int32Value());
8966 // Create new environment reusing the global object.
8967 LocalContext env(NULL, instance_template, global_object);
8968 Local<Value> value = Script::Compile(v8_str("x"))->Run();
8969 CHECK_EQ(42, value->Int32Value());
8970 value = Script::Compile(v8_str("f()"))->Run();
8971 CHECK_EQ(12, value->Int32Value());
8972 value = Script::Compile(v8_str(script))->Run();
8973 CHECK_EQ(1, value->Int32Value());
8978 THREADED_TEST(CallKnownGlobalReceiver) {
8979 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
8981 Local<Value> global_object;
8983 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
8984 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
8986 // The script to check that we leave global object not
8987 // global object proxy on stack when we deoptimize from inside
8988 // arguments evaluation.
8989 // To provoke error we need to both force deoptimization
8990 // from arguments evaluation and to force CallIC to take
8991 // CallIC_Miss code path that can't cope with global proxy.
8992 const char* script =
8993 "function bar(x, y) { try { } finally { } }"
8994 "function baz(x) { try { } finally { } }"
8995 "function bom(x) { try { } finally { } }"
8996 "function foo(x) { bar([x], bom(2)); }"
8997 "for (var i = 0; i < 10000; i++) foo(1);"
9002 LocalContext env(NULL, instance_template);
9003 // Hold on to the global object so it can be used again in another
9004 // environment initialization.
9005 global_object = env->Global();
9006 foo = Script::Compile(v8_str(script))->Run();
9010 // Create new environment reusing the global object.
9011 LocalContext env(NULL, instance_template, global_object);
9012 env->Global()->Set(v8_str("foo"), foo);
9013 Script::Compile(v8_str("foo()"))->Run();
9018 static void ShadowFunctionCallback(
9019 const v8::FunctionCallbackInfo<v8::Value>& args) {
9020 ApiTestFuzzer::Fuzz();
9021 args.GetReturnValue().Set(v8_num(42));
9025 static int shadow_y;
9026 static int shadow_y_setter_call_count;
9027 static int shadow_y_getter_call_count;
9030 static void ShadowYSetter(Local<String>,
9032 const v8::PropertyCallbackInfo<void>&) {
9033 shadow_y_setter_call_count++;
9038 static void ShadowYGetter(Local<String> name,
9039 const v8::PropertyCallbackInfo<v8::Value>& info) {
9040 ApiTestFuzzer::Fuzz();
9041 shadow_y_getter_call_count++;
9042 info.GetReturnValue().Set(v8_num(shadow_y));
9046 static void ShadowIndexedGet(uint32_t index,
9047 const v8::PropertyCallbackInfo<v8::Value>&) {
9051 static void ShadowNamedGet(Local<String> key,
9052 const v8::PropertyCallbackInfo<v8::Value>&) {
9056 THREADED_TEST(ShadowObject) {
9057 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9058 v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
9060 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New();
9061 LocalContext context(NULL, global_template);
9063 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9064 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
9065 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
9066 Local<ObjectTemplate> proto = t->PrototypeTemplate();
9067 Local<ObjectTemplate> instance = t->InstanceTemplate();
9069 proto->Set(v8_str("f"),
9070 v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>()));
9071 proto->Set(v8_str("x"), v8_num(12));
9073 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9075 Local<Value> o = t->GetFunction()->NewInstance();
9076 context->Global()->Set(v8_str("__proto__"), o);
9078 Local<Value> value =
9079 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run();
9080 CHECK(value->IsBoolean());
9081 CHECK(!value->BooleanValue());
9083 value = Script::Compile(v8_str("x"))->Run();
9084 CHECK_EQ(12, value->Int32Value());
9086 value = Script::Compile(v8_str("f()"))->Run();
9087 CHECK_EQ(42, value->Int32Value());
9089 Script::Compile(v8_str("y = 43"))->Run();
9090 CHECK_EQ(1, shadow_y_setter_call_count);
9091 value = Script::Compile(v8_str("y"))->Run();
9092 CHECK_EQ(1, shadow_y_getter_call_count);
9093 CHECK_EQ(42, value->Int32Value());
9097 THREADED_TEST(HiddenPrototype) {
9098 LocalContext context;
9099 v8::HandleScope handle_scope(context->GetIsolate());
9101 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
9102 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9103 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9104 t1->SetHiddenPrototype(true);
9105 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9106 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9107 t2->SetHiddenPrototype(true);
9108 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9109 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9110 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9112 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9113 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9114 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9115 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9117 // Setting the prototype on an object skips hidden prototypes.
9118 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9119 o0->Set(v8_str("__proto__"), o1);
9120 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9121 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9122 o0->Set(v8_str("__proto__"), o2);
9123 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9124 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9125 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9126 o0->Set(v8_str("__proto__"), o3);
9127 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9128 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9129 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9130 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9132 // Getting the prototype of o0 should get the first visible one
9133 // which is o3. Therefore, z should not be defined on the prototype
9135 Local<Value> proto = o0->Get(v8_str("__proto__"));
9136 CHECK(proto->IsObject());
9137 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
9141 THREADED_TEST(HiddenPrototypeSet) {
9142 LocalContext context;
9143 v8::HandleScope handle_scope(context->GetIsolate());
9145 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New();
9146 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New();
9147 ht->SetHiddenPrototype(true);
9148 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New();
9149 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9151 Local<v8::Object> o = ot->GetFunction()->NewInstance();
9152 Local<v8::Object> h = ht->GetFunction()->NewInstance();
9153 Local<v8::Object> p = pt->GetFunction()->NewInstance();
9154 o->Set(v8_str("__proto__"), h);
9155 h->Set(v8_str("__proto__"), p);
9157 // Setting a property that exists on the hidden prototype goes there.
9158 o->Set(v8_str("x"), v8_num(7));
9159 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
9160 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
9161 CHECK(p->Get(v8_str("x"))->IsUndefined());
9163 // Setting a new property should not be forwarded to the hidden prototype.
9164 o->Set(v8_str("y"), v8_num(6));
9165 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
9166 CHECK(h->Get(v8_str("y"))->IsUndefined());
9167 CHECK(p->Get(v8_str("y"))->IsUndefined());
9169 // Setting a property that only exists on a prototype of the hidden prototype
9170 // is treated normally again.
9171 p->Set(v8_str("z"), v8_num(8));
9172 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
9173 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9174 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9175 o->Set(v8_str("z"), v8_num(9));
9176 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
9177 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9178 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9182 // Regression test for issue 2457.
9183 THREADED_TEST(HiddenPrototypeIdentityHash) {
9184 LocalContext context;
9185 v8::HandleScope handle_scope(context->GetIsolate());
9187 Handle<FunctionTemplate> t = FunctionTemplate::New();
9188 t->SetHiddenPrototype(true);
9189 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
9190 Handle<Object> p = t->GetFunction()->NewInstance();
9191 Handle<Object> o = Object::New();
9194 int hash = o->GetIdentityHash();
9196 o->Set(v8_str("foo"), v8_num(42));
9197 ASSERT_EQ(hash, o->GetIdentityHash());
9201 THREADED_TEST(SetPrototype) {
9202 LocalContext context;
9203 v8::HandleScope handle_scope(context->GetIsolate());
9205 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
9206 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9207 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9208 t1->SetHiddenPrototype(true);
9209 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9210 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9211 t2->SetHiddenPrototype(true);
9212 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9213 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9214 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9216 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9217 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9218 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9219 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9221 // Setting the prototype on an object does not skip hidden prototypes.
9222 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9223 CHECK(o0->SetPrototype(o1));
9224 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9225 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9226 CHECK(o1->SetPrototype(o2));
9227 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9228 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9229 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9230 CHECK(o2->SetPrototype(o3));
9231 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9232 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9233 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9234 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9236 // Getting the prototype of o0 should get the first visible one
9237 // which is o3. Therefore, z should not be defined on the prototype
9239 Local<Value> proto = o0->Get(v8_str("__proto__"));
9240 CHECK(proto->IsObject());
9241 CHECK_EQ(proto.As<v8::Object>(), o3);
9243 // However, Object::GetPrototype ignores hidden prototype.
9244 Local<Value> proto0 = o0->GetPrototype();
9245 CHECK(proto0->IsObject());
9246 CHECK_EQ(proto0.As<v8::Object>(), o1);
9248 Local<Value> proto1 = o1->GetPrototype();
9249 CHECK(proto1->IsObject());
9250 CHECK_EQ(proto1.As<v8::Object>(), o2);
9252 Local<Value> proto2 = o2->GetPrototype();
9253 CHECK(proto2->IsObject());
9254 CHECK_EQ(proto2.As<v8::Object>(), o3);
9258 // Getting property names of an object with a prototype chain that
9259 // triggers dictionary elements in GetLocalPropertyNames() shouldn't
9260 // crash the runtime.
9261 THREADED_TEST(Regress91517) {
9262 i::FLAG_allow_natives_syntax = true;
9263 LocalContext context;
9264 v8::HandleScope handle_scope(context->GetIsolate());
9266 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9267 t1->SetHiddenPrototype(true);
9268 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
9269 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9270 t2->SetHiddenPrototype(true);
9271 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
9272 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New());
9273 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
9274 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
9275 t3->SetHiddenPrototype(true);
9276 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
9277 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New();
9278 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
9280 // Force dictionary-based properties.
9281 i::ScopedVector<char> name_buf(1024);
9282 for (int i = 1; i <= 1000; i++) {
9283 i::OS::SNPrintF(name_buf, "sdf%d", i);
9284 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
9287 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9288 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9289 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9290 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
9292 // Create prototype chain of hidden prototypes.
9293 CHECK(o4->SetPrototype(o3));
9294 CHECK(o3->SetPrototype(o2));
9295 CHECK(o2->SetPrototype(o1));
9297 // Call the runtime version of GetLocalPropertyNames() on the natively
9298 // created object through JavaScript.
9299 context->Global()->Set(v8_str("obj"), o4);
9300 CompileRun("var names = %GetLocalPropertyNames(obj, true);");
9302 ExpectInt32("names.length", 1006);
9303 ExpectTrue("names.indexOf(\"baz\") >= 0");
9304 ExpectTrue("names.indexOf(\"boo\") >= 0");
9305 ExpectTrue("names.indexOf(\"foo\") >= 0");
9306 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
9307 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
9308 ExpectFalse("names[1005] == undefined");
9312 THREADED_TEST(FunctionReadOnlyPrototype) {
9313 LocalContext context;
9314 v8::HandleScope handle_scope(context->GetIsolate());
9316 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
9317 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
9318 t1->ReadOnlyPrototype();
9319 context->Global()->Set(v8_str("func1"), t1->GetFunction());
9320 // Configured value of ReadOnly flag.
9323 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
9324 " return (descriptor['writable'] == false);"
9325 "})()")->BooleanValue());
9326 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
9328 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
9330 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
9331 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42));
9332 context->Global()->Set(v8_str("func2"), t2->GetFunction());
9333 // Default value of ReadOnly flag.
9336 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
9337 " return (descriptor['writable'] == true);"
9338 "})()")->BooleanValue());
9339 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
9343 THREADED_TEST(SetPrototypeThrows) {
9344 LocalContext context;
9345 v8::HandleScope handle_scope(context->GetIsolate());
9347 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9349 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
9350 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
9352 CHECK(o0->SetPrototype(o1));
9353 // If setting the prototype leads to the cycle, SetPrototype should
9354 // return false and keep VM in sane state.
9355 v8::TryCatch try_catch;
9356 CHECK(!o1->SetPrototype(o0));
9357 CHECK(!try_catch.HasCaught());
9358 ASSERT(!i::Isolate::Current()->has_pending_exception());
9360 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
9364 THREADED_TEST(GetterSetterExceptions) {
9365 LocalContext context;
9366 v8::HandleScope handle_scope(context->GetIsolate());
9368 "function Foo() { };"
9369 "function Throw() { throw 5; };"
9371 "x.__defineSetter__('set', Throw);"
9372 "x.__defineGetter__('get', Throw);");
9373 Local<v8::Object> x =
9374 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
9375 v8::TryCatch try_catch;
9376 x->Set(v8_str("set"), v8::Integer::New(8));
9377 x->Get(v8_str("get"));
9378 x->Set(v8_str("set"), v8::Integer::New(8));
9379 x->Get(v8_str("get"));
9380 x->Set(v8_str("set"), v8::Integer::New(8));
9381 x->Get(v8_str("get"));
9382 x->Set(v8_str("set"), v8::Integer::New(8));
9383 x->Get(v8_str("get"));
9387 THREADED_TEST(Constructor) {
9388 LocalContext context;
9389 v8::HandleScope handle_scope(context->GetIsolate());
9390 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9391 templ->SetClassName(v8_str("Fun"));
9392 Local<Function> cons = templ->GetFunction();
9393 context->Global()->Set(v8_str("Fun"), cons);
9394 Local<v8::Object> inst = cons->NewInstance();
9395 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
9396 CHECK(obj->IsJSObject());
9397 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
9398 CHECK(value->BooleanValue());
9402 static void ConstructorCallback(
9403 const v8::FunctionCallbackInfo<v8::Value>& args) {
9404 ApiTestFuzzer::Fuzz();
9407 if (args.IsConstructCall()) {
9408 Local<Object> Holder = args.Holder();
9409 This = Object::New();
9410 Local<Value> proto = Holder->GetPrototype();
9411 if (proto->IsObject()) {
9412 This->SetPrototype(proto);
9418 This->Set(v8_str("a"), args[0]);
9419 args.GetReturnValue().Set(This);
9423 static void FakeConstructorCallback(
9424 const v8::FunctionCallbackInfo<v8::Value>& args) {
9425 ApiTestFuzzer::Fuzz();
9426 args.GetReturnValue().Set(args[0]);
9430 THREADED_TEST(ConstructorForObject) {
9431 LocalContext context;
9432 v8::HandleScope handle_scope(context->GetIsolate());
9434 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9435 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
9436 Local<Object> instance = instance_template->NewInstance();
9437 context->Global()->Set(v8_str("obj"), instance);
9438 v8::TryCatch try_catch;
9440 CHECK(!try_catch.HasCaught());
9442 // Call the Object's constructor with a 32-bit signed integer.
9443 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
9444 CHECK(!try_catch.HasCaught());
9445 CHECK(value->IsInt32());
9446 CHECK_EQ(28, value->Int32Value());
9448 Local<Value> args1[] = { v8_num(28) };
9449 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
9450 CHECK(value_obj1->IsObject());
9451 Local<Object> object1 = Local<Object>::Cast(value_obj1);
9452 value = object1->Get(v8_str("a"));
9453 CHECK(value->IsInt32());
9454 CHECK(!try_catch.HasCaught());
9455 CHECK_EQ(28, value->Int32Value());
9457 // Call the Object's constructor with a String.
9459 "(function() { var o = new obj('tipli'); return o.a; })()");
9460 CHECK(!try_catch.HasCaught());
9461 CHECK(value->IsString());
9462 String::Utf8Value string_value1(value->ToString());
9463 CHECK_EQ("tipli", *string_value1);
9465 Local<Value> args2[] = { v8_str("tipli") };
9466 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
9467 CHECK(value_obj2->IsObject());
9468 Local<Object> object2 = Local<Object>::Cast(value_obj2);
9469 value = object2->Get(v8_str("a"));
9470 CHECK(!try_catch.HasCaught());
9471 CHECK(value->IsString());
9472 String::Utf8Value string_value2(value->ToString());
9473 CHECK_EQ("tipli", *string_value2);
9475 // Call the Object's constructor with a Boolean.
9476 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
9477 CHECK(!try_catch.HasCaught());
9478 CHECK(value->IsBoolean());
9479 CHECK_EQ(true, value->BooleanValue());
9481 Handle<Value> args3[] = { v8::True() };
9482 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
9483 CHECK(value_obj3->IsObject());
9484 Local<Object> object3 = Local<Object>::Cast(value_obj3);
9485 value = object3->Get(v8_str("a"));
9486 CHECK(!try_catch.HasCaught());
9487 CHECK(value->IsBoolean());
9488 CHECK_EQ(true, value->BooleanValue());
9490 // Call the Object's constructor with undefined.
9491 Handle<Value> args4[] = { v8::Undefined() };
9492 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
9493 CHECK(value_obj4->IsObject());
9494 Local<Object> object4 = Local<Object>::Cast(value_obj4);
9495 value = object4->Get(v8_str("a"));
9496 CHECK(!try_catch.HasCaught());
9497 CHECK(value->IsUndefined());
9499 // Call the Object's constructor with null.
9500 Handle<Value> args5[] = { v8::Null() };
9501 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
9502 CHECK(value_obj5->IsObject());
9503 Local<Object> object5 = Local<Object>::Cast(value_obj5);
9504 value = object5->Get(v8_str("a"));
9505 CHECK(!try_catch.HasCaught());
9506 CHECK(value->IsNull());
9509 // Check exception handling when there is no constructor set for the Object.
9510 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9511 Local<Object> instance = instance_template->NewInstance();
9512 context->Global()->Set(v8_str("obj2"), instance);
9513 v8::TryCatch try_catch;
9515 CHECK(!try_catch.HasCaught());
9517 value = CompileRun("new obj2(28)");
9518 CHECK(try_catch.HasCaught());
9519 String::Utf8Value exception_value1(try_catch.Exception());
9520 CHECK_EQ("TypeError: object is not a function", *exception_value1);
9523 Local<Value> args[] = { v8_num(29) };
9524 value = instance->CallAsConstructor(1, args);
9525 CHECK(try_catch.HasCaught());
9526 String::Utf8Value exception_value2(try_catch.Exception());
9527 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
9531 // Check the case when constructor throws exception.
9532 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9533 instance_template->SetCallAsFunctionHandler(ThrowValue);
9534 Local<Object> instance = instance_template->NewInstance();
9535 context->Global()->Set(v8_str("obj3"), instance);
9536 v8::TryCatch try_catch;
9538 CHECK(!try_catch.HasCaught());
9540 value = CompileRun("new obj3(22)");
9541 CHECK(try_catch.HasCaught());
9542 String::Utf8Value exception_value1(try_catch.Exception());
9543 CHECK_EQ("22", *exception_value1);
9546 Local<Value> args[] = { v8_num(23) };
9547 value = instance->CallAsConstructor(1, args);
9548 CHECK(try_catch.HasCaught());
9549 String::Utf8Value exception_value2(try_catch.Exception());
9550 CHECK_EQ("23", *exception_value2);
9554 // Check whether constructor returns with an object or non-object.
9555 { Local<FunctionTemplate> function_template =
9556 FunctionTemplate::New(FakeConstructorCallback);
9557 Local<Function> function = function_template->GetFunction();
9558 Local<Object> instance1 = function;
9559 context->Global()->Set(v8_str("obj4"), instance1);
9560 v8::TryCatch try_catch;
9562 CHECK(!try_catch.HasCaught());
9564 CHECK(instance1->IsObject());
9565 CHECK(instance1->IsFunction());
9567 value = CompileRun("new obj4(28)");
9568 CHECK(!try_catch.HasCaught());
9569 CHECK(value->IsObject());
9571 Local<Value> args1[] = { v8_num(28) };
9572 value = instance1->CallAsConstructor(1, args1);
9573 CHECK(!try_catch.HasCaught());
9574 CHECK(value->IsObject());
9576 Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9577 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
9578 Local<Object> instance2 = instance_template->NewInstance();
9579 context->Global()->Set(v8_str("obj5"), instance2);
9580 CHECK(!try_catch.HasCaught());
9582 CHECK(instance2->IsObject());
9583 CHECK(!instance2->IsFunction());
9585 value = CompileRun("new obj5(28)");
9586 CHECK(!try_catch.HasCaught());
9587 CHECK(!value->IsObject());
9589 Local<Value> args2[] = { v8_num(28) };
9590 value = instance2->CallAsConstructor(1, args2);
9591 CHECK(!try_catch.HasCaught());
9592 CHECK(!value->IsObject());
9597 THREADED_TEST(FunctionDescriptorException) {
9598 LocalContext context;
9599 v8::HandleScope handle_scope(context->GetIsolate());
9600 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
9601 templ->SetClassName(v8_str("Fun"));
9602 Local<Function> cons = templ->GetFunction();
9603 context->Global()->Set(v8_str("Fun"), cons);
9604 Local<Value> value = CompileRun(
9607 " (new Fun()).blah()"
9609 " var str = String(e);"
9610 " if (str.indexOf('TypeError') == -1) return 1;"
9611 " if (str.indexOf('[object Fun]') != -1) return 2;"
9612 " if (str.indexOf('#<Fun>') == -1) return 3;"
9618 CHECK_EQ(0, value->Int32Value());
9622 THREADED_TEST(EvalAliasedDynamic) {
9623 LocalContext current;
9624 v8::HandleScope scope(current->GetIsolate());
9626 // Tests where aliased eval can only be resolved dynamically.
9627 Local<Script> script =
9628 Script::Compile(v8_str("function f(x) { "
9630 " with (x) { return eval('foo'); }"
9633 "result1 = f(new Object());"
9634 "result2 = f(this);"
9635 "var x = new Object();"
9636 "x.eval = function(x) { return 1; };"
9637 "result3 = f(x);"));
9639 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
9640 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
9641 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
9643 v8::TryCatch try_catch;
9645 Script::Compile(v8_str("function f(x) { "
9647 " with (x) { return eval('bar'); }"
9649 "result4 = f(this)"));
9651 CHECK(!try_catch.HasCaught());
9652 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
9658 THREADED_TEST(CrossEval) {
9659 v8::HandleScope scope(v8::Isolate::GetCurrent());
9661 LocalContext current;
9663 Local<String> token = v8_str("<security token>");
9664 other->SetSecurityToken(token);
9665 current->SetSecurityToken(token);
9667 // Set up reference from current to other.
9668 current->Global()->Set(v8_str("other"), other->Global());
9670 // Check that new variables are introduced in other context.
9671 Local<Script> script =
9672 Script::Compile(v8_str("other.eval('var foo = 1234')"));
9674 Local<Value> foo = other->Global()->Get(v8_str("foo"));
9675 CHECK_EQ(1234, foo->Int32Value());
9676 CHECK(!current->Global()->Has(v8_str("foo")));
9678 // Check that writing to non-existing properties introduces them in
9679 // the other context.
9681 Script::Compile(v8_str("other.eval('na = 1234')"));
9683 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
9684 CHECK(!current->Global()->Has(v8_str("na")));
9686 // Check that global variables in current context are not visible in other
9688 v8::TryCatch try_catch;
9690 Script::Compile(v8_str("var bar = 42; other.eval('bar');"));
9691 Local<Value> result = script->Run();
9692 CHECK(try_catch.HasCaught());
9695 // Check that local variables in current context are not visible in other
9698 Script::Compile(v8_str("(function() { "
9700 " return other.eval('baz');"
9702 result = script->Run();
9703 CHECK(try_catch.HasCaught());
9706 // Check that global variables in the other environment are visible
9707 // when evaluting code.
9708 other->Global()->Set(v8_str("bis"), v8_num(1234));
9709 script = Script::Compile(v8_str("other.eval('bis')"));
9710 CHECK_EQ(1234, script->Run()->Int32Value());
9711 CHECK(!try_catch.HasCaught());
9713 // Check that the 'this' pointer points to the global object evaluating
9715 other->Global()->Set(v8_str("t"), other->Global());
9716 script = Script::Compile(v8_str("other.eval('this == t')"));
9717 result = script->Run();
9718 CHECK(result->IsTrue());
9719 CHECK(!try_catch.HasCaught());
9721 // Check that variables introduced in with-statement are not visible in
9724 Script::Compile(v8_str("with({x:2}){other.eval('x')}"));
9725 result = script->Run();
9726 CHECK(try_catch.HasCaught());
9729 // Check that you cannot use 'eval.call' with another object than the
9730 // current global object.
9732 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')"));
9733 result = script->Run();
9734 CHECK(try_catch.HasCaught());
9738 // Test that calling eval in a context which has been detached from
9739 // its global throws an exception. This behavior is consistent with
9740 // other JavaScript implementations.
9741 THREADED_TEST(EvalInDetachedGlobal) {
9742 v8::Isolate* isolate = v8::Isolate::GetCurrent();
9743 v8::HandleScope scope(isolate);
9745 v8::Local<Context> context0 = Context::New(isolate);
9746 v8::Local<Context> context1 = Context::New(isolate);
9748 // Set up function in context0 that uses eval from context0.
9750 v8::Handle<v8::Value> fun =
9751 CompileRun("var x = 42;"
9754 " return function(s) { return e(s); }"
9758 // Put the function into context1 and call it before and after
9759 // detaching the global. Before detaching, the call succeeds and
9760 // after detaching and exception is thrown.
9762 context1->Global()->Set(v8_str("fun"), fun);
9763 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
9764 CHECK_EQ(42, x_value->Int32Value());
9765 context0->DetachGlobal();
9766 v8::TryCatch catcher;
9767 x_value = CompileRun("fun('x')");
9768 CHECK(x_value.IsEmpty());
9769 CHECK(catcher.HasCaught());
9774 THREADED_TEST(CrossLazyLoad) {
9775 v8::HandleScope scope(v8::Isolate::GetCurrent());
9777 LocalContext current;
9779 Local<String> token = v8_str("<security token>");
9780 other->SetSecurityToken(token);
9781 current->SetSecurityToken(token);
9783 // Set up reference from current to other.
9784 current->Global()->Set(v8_str("other"), other->Global());
9786 // Trigger lazy loading in other context.
9787 Local<Script> script =
9788 Script::Compile(v8_str("other.eval('new Date(42)')"));
9789 Local<Value> value = script->Run();
9790 CHECK_EQ(42.0, value->NumberValue());
9794 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
9795 ApiTestFuzzer::Fuzz();
9796 if (args.IsConstructCall()) {
9797 if (args[0]->IsInt32()) {
9798 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
9803 args.GetReturnValue().Set(args[0]);
9807 // Test that a call handler can be set for objects which will allow
9808 // non-function objects created through the API to be called as
9810 THREADED_TEST(CallAsFunction) {
9811 LocalContext context;
9812 v8::HandleScope scope(context->GetIsolate());
9814 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9815 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9816 instance_template->SetCallAsFunctionHandler(call_as_function);
9817 Local<v8::Object> instance = t->GetFunction()->NewInstance();
9818 context->Global()->Set(v8_str("obj"), instance);
9819 v8::TryCatch try_catch;
9821 CHECK(!try_catch.HasCaught());
9823 value = CompileRun("obj(42)");
9824 CHECK(!try_catch.HasCaught());
9825 CHECK_EQ(42, value->Int32Value());
9827 value = CompileRun("(function(o){return o(49)})(obj)");
9828 CHECK(!try_catch.HasCaught());
9829 CHECK_EQ(49, value->Int32Value());
9831 // test special case of call as function
9832 value = CompileRun("[obj]['0'](45)");
9833 CHECK(!try_catch.HasCaught());
9834 CHECK_EQ(45, value->Int32Value());
9836 value = CompileRun("obj.call = Function.prototype.call;"
9837 "obj.call(null, 87)");
9838 CHECK(!try_catch.HasCaught());
9839 CHECK_EQ(87, value->Int32Value());
9841 // Regression tests for bug #1116356: Calling call through call/apply
9842 // must work for non-function receivers.
9843 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
9844 value = CompileRun(apply_99);
9845 CHECK(!try_catch.HasCaught());
9846 CHECK_EQ(99, value->Int32Value());
9848 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
9849 value = CompileRun(call_17);
9850 CHECK(!try_catch.HasCaught());
9851 CHECK_EQ(17, value->Int32Value());
9853 // Check that the call-as-function handler can be called through
9855 value = CompileRun("new obj(43)");
9856 CHECK(!try_catch.HasCaught());
9857 CHECK_EQ(-43, value->Int32Value());
9859 // Check that the call-as-function handler can be called through
9861 v8::Handle<Value> args[] = { v8_num(28) };
9862 value = instance->CallAsFunction(instance, 1, args);
9863 CHECK(!try_catch.HasCaught());
9864 CHECK_EQ(28, value->Int32Value());
9867 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9868 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
9869 USE(instance_template);
9870 Local<v8::Object> instance = t->GetFunction()->NewInstance();
9871 context->Global()->Set(v8_str("obj2"), instance);
9872 v8::TryCatch try_catch;
9874 CHECK(!try_catch.HasCaught());
9876 // Call an object without call-as-function handler through the JS
9877 value = CompileRun("obj2(28)");
9878 CHECK(value.IsEmpty());
9879 CHECK(try_catch.HasCaught());
9880 String::Utf8Value exception_value1(try_catch.Exception());
9881 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function",
9885 // Call an object without call-as-function handler through the API
9886 value = CompileRun("obj2(28)");
9887 v8::Handle<Value> args[] = { v8_num(28) };
9888 value = instance->CallAsFunction(instance, 1, args);
9889 CHECK(value.IsEmpty());
9890 CHECK(try_catch.HasCaught());
9891 String::Utf8Value exception_value2(try_catch.Exception());
9892 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
9896 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
9897 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9898 instance_template->SetCallAsFunctionHandler(ThrowValue);
9899 Local<v8::Object> instance = t->GetFunction()->NewInstance();
9900 context->Global()->Set(v8_str("obj3"), instance);
9901 v8::TryCatch try_catch;
9903 CHECK(!try_catch.HasCaught());
9905 // Catch the exception which is thrown by call-as-function handler
9906 value = CompileRun("obj3(22)");
9907 CHECK(try_catch.HasCaught());
9908 String::Utf8Value exception_value1(try_catch.Exception());
9909 CHECK_EQ("22", *exception_value1);
9912 v8::Handle<Value> args[] = { v8_num(23) };
9913 value = instance->CallAsFunction(instance, 1, args);
9914 CHECK(try_catch.HasCaught());
9915 String::Utf8Value exception_value2(try_catch.Exception());
9916 CHECK_EQ("23", *exception_value2);
9922 // Check whether a non-function object is callable.
9923 THREADED_TEST(CallableObject) {
9924 LocalContext context;
9925 v8::HandleScope scope(context->GetIsolate());
9927 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9928 instance_template->SetCallAsFunctionHandler(call_as_function);
9929 Local<Object> instance = instance_template->NewInstance();
9930 v8::TryCatch try_catch;
9932 CHECK(instance->IsCallable());
9933 CHECK(!try_catch.HasCaught());
9936 { Local<ObjectTemplate> instance_template = ObjectTemplate::New();
9937 Local<Object> instance = instance_template->NewInstance();
9938 v8::TryCatch try_catch;
9940 CHECK(!instance->IsCallable());
9941 CHECK(!try_catch.HasCaught());
9944 { Local<FunctionTemplate> function_template =
9945 FunctionTemplate::New(call_as_function);
9946 Local<Function> function = function_template->GetFunction();
9947 Local<Object> instance = function;
9948 v8::TryCatch try_catch;
9950 CHECK(instance->IsCallable());
9951 CHECK(!try_catch.HasCaught());
9954 { Local<FunctionTemplate> function_template = FunctionTemplate::New();
9955 Local<Function> function = function_template->GetFunction();
9956 Local<Object> instance = function;
9957 v8::TryCatch try_catch;
9959 CHECK(instance->IsCallable());
9960 CHECK(!try_catch.HasCaught());
9965 static int CountHandles() {
9966 return v8::HandleScope::NumberOfHandles();
9970 static int Recurse(int depth, int iterations) {
9971 v8::HandleScope scope(v8::Isolate::GetCurrent());
9972 if (depth == 0) return CountHandles();
9973 for (int i = 0; i < iterations; i++) {
9974 Local<v8::Number> n(v8::Integer::New(42));
9976 return Recurse(depth - 1, iterations);
9980 THREADED_TEST(HandleIteration) {
9981 static const int kIterations = 500;
9982 static const int kNesting = 200;
9983 CHECK_EQ(0, CountHandles());
9985 v8::HandleScope scope1(v8::Isolate::GetCurrent());
9986 CHECK_EQ(0, CountHandles());
9987 for (int i = 0; i < kIterations; i++) {
9988 Local<v8::Number> n(v8::Integer::New(42));
9989 CHECK_EQ(i + 1, CountHandles());
9992 CHECK_EQ(kIterations, CountHandles());
9994 v8::HandleScope scope2(v8::Isolate::GetCurrent());
9995 for (int j = 0; j < kIterations; j++) {
9996 Local<v8::Number> n(v8::Integer::New(42));
9997 CHECK_EQ(j + 1 + kIterations, CountHandles());
10000 CHECK_EQ(kIterations, CountHandles());
10002 CHECK_EQ(0, CountHandles());
10003 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations));
10007 static void InterceptorHasOwnPropertyGetter(
10008 Local<String> name,
10009 const v8::PropertyCallbackInfo<v8::Value>& info) {
10010 ApiTestFuzzer::Fuzz();
10014 THREADED_TEST(InterceptorHasOwnProperty) {
10015 LocalContext context;
10016 v8::HandleScope scope(context->GetIsolate());
10017 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10018 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
10019 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
10020 Local<Function> function = fun_templ->GetFunction();
10021 context->Global()->Set(v8_str("constructor"), function);
10022 v8::Handle<Value> value = CompileRun(
10023 "var o = new constructor();"
10024 "o.hasOwnProperty('ostehaps');");
10025 CHECK_EQ(false, value->BooleanValue());
10026 value = CompileRun(
10028 "o.hasOwnProperty('ostehaps');");
10029 CHECK_EQ(true, value->BooleanValue());
10030 value = CompileRun(
10031 "var p = new constructor();"
10032 "p.hasOwnProperty('ostehaps');");
10033 CHECK_EQ(false, value->BooleanValue());
10037 static void InterceptorHasOwnPropertyGetterGC(
10038 Local<String> name,
10039 const v8::PropertyCallbackInfo<v8::Value>& info) {
10040 ApiTestFuzzer::Fuzz();
10041 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10045 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
10046 LocalContext context;
10047 v8::HandleScope scope(context->GetIsolate());
10048 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10049 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
10050 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
10051 Local<Function> function = fun_templ->GetFunction();
10052 context->Global()->Set(v8_str("constructor"), function);
10053 // Let's first make some stuff so we can be sure to get a good GC.
10055 "function makestr(size) {"
10057 " case 1: return 'f';"
10058 " case 2: return 'fo';"
10059 " case 3: return 'foo';"
10061 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
10063 "var x = makestr(12345);"
10064 "x = makestr(31415);"
10065 "x = makestr(23456);");
10066 v8::Handle<Value> value = CompileRun(
10067 "var o = new constructor();"
10068 "o.__proto__ = new String(x);"
10069 "o.hasOwnProperty('ostehaps');");
10070 CHECK_EQ(false, value->BooleanValue());
10074 typedef void (*NamedPropertyGetter)(
10075 Local<String> property,
10076 const v8::PropertyCallbackInfo<v8::Value>& info);
10079 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
10080 const char* source,
10082 v8::HandleScope scope(v8::Isolate::GetCurrent());
10083 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10084 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
10085 LocalContext context;
10086 context->Global()->Set(v8_str("o"), templ->NewInstance());
10087 v8::Handle<Value> value = CompileRun(source);
10088 CHECK_EQ(expected, value->Int32Value());
10092 static void InterceptorLoadICGetter(
10093 Local<String> name,
10094 const v8::PropertyCallbackInfo<v8::Value>& info) {
10095 ApiTestFuzzer::Fuzz();
10096 v8::Isolate* isolate = v8::Isolate::GetCurrent();
10097 CHECK_EQ(isolate, info.GetIsolate());
10098 CHECK_EQ(v8_str("data"), info.Data());
10099 CHECK_EQ(v8_str("x"), name);
10100 info.GetReturnValue().Set(v8::Integer::New(42));
10104 // This test should hit the load IC for the interceptor case.
10105 THREADED_TEST(InterceptorLoadIC) {
10106 CheckInterceptorLoadIC(InterceptorLoadICGetter,
10108 "for (var i = 0; i < 1000; i++) {"
10115 // Below go several tests which verify that JITing for various
10116 // configurations of interceptor and explicit fields works fine
10117 // (those cases are special cased to get better performance).
10119 static void InterceptorLoadXICGetter(
10120 Local<String> name,
10121 const v8::PropertyCallbackInfo<v8::Value>& info) {
10122 ApiTestFuzzer::Fuzz();
10123 info.GetReturnValue().Set(
10124 v8_str("x")->Equals(name) ?
10125 v8::Handle<v8::Value>(v8::Integer::New(42)) :
10126 v8::Handle<v8::Value>());
10130 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
10131 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10134 "for (var i = 0; i < 1000; i++) {"
10141 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
10142 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10144 "o.__proto__ = { 'y': 239 };"
10145 "for (var i = 0; i < 1000; i++) {"
10146 " result = o.y + o.x;"
10152 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
10153 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10155 "o.__proto__.y = 239;"
10156 "for (var i = 0; i < 1000; i++) {"
10157 " result = o.y + o.x;"
10163 THREADED_TEST(InterceptorLoadICUndefined) {
10164 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10166 "for (var i = 0; i < 1000; i++) {"
10167 " result = (o.y == undefined) ? 239 : 42;"
10173 THREADED_TEST(InterceptorLoadICWithOverride) {
10174 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10175 "fst = new Object(); fst.__proto__ = o;"
10176 "snd = new Object(); snd.__proto__ = fst;"
10178 "for (var i = 0; i < 1000; i++) {"
10179 " result1 = snd.x;"
10183 "for (var i = 0; i < 1000; i++) {"
10186 "result + result1",
10191 // Test the case when we stored field into
10192 // a stub, but interceptor produced value on its own.
10193 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
10194 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10195 "proto = new Object();"
10196 "o.__proto__ = proto;"
10198 "for (var i = 0; i < 1000; i++) {"
10200 // Now it should be ICed and keep a reference to x defined on proto
10203 "for (var i = 0; i < 1000; i++) {"
10211 // Test the case when we stored field into
10212 // a stub, but it got invalidated later on.
10213 THREADED_TEST(InterceptorLoadICInvalidatedField) {
10214 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10215 "proto1 = new Object();"
10216 "proto2 = new Object();"
10217 "o.__proto__ = proto1;"
10218 "proto1.__proto__ = proto2;"
10220 "for (var i = 0; i < 1000; i++) {"
10222 // Now it should be ICed and keep a reference to y defined on proto2
10226 "for (var i = 0; i < 1000; i++) {"
10234 static int interceptor_load_not_handled_calls = 0;
10235 static void InterceptorLoadNotHandled(
10236 Local<String> name,
10237 const v8::PropertyCallbackInfo<v8::Value>& info) {
10238 ++interceptor_load_not_handled_calls;
10242 // Test how post-interceptor lookups are done in the non-cacheable
10243 // case: the interceptor should not be invoked during this lookup.
10244 THREADED_TEST(InterceptorLoadICPostInterceptor) {
10245 interceptor_load_not_handled_calls = 0;
10246 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
10247 "receiver = new Object();"
10248 "receiver.__proto__ = o;"
10249 "proto = new Object();"
10250 "/* Make proto a slow-case object. */"
10251 "for (var i = 0; i < 1000; i++) {"
10252 " proto[\"xxxxxxxx\" + i] = [];"
10255 "o.__proto__ = proto;"
10257 "for (var i = 0; i < 1000; i++) {"
10258 " result += receiver.x;"
10262 CHECK_EQ(1000, interceptor_load_not_handled_calls);
10266 // Test the case when we stored field into
10267 // a stub, but it got invalidated later on due to override on
10268 // global object which is between interceptor and fields' holders.
10269 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
10270 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
10271 "o.__proto__ = this;" // set a global to be a proto of o.
10272 "this.__proto__.y = 239;"
10273 "for (var i = 0; i < 10; i++) {"
10274 " if (o.y != 239) throw 'oops: ' + o.y;"
10275 // Now it should be ICed and keep a reference to y defined on field_holder.
10277 "this.y = 42;" // Assign on a global.
10279 "for (var i = 0; i < 10; i++) {"
10287 static void SetOnThis(Local<String> name,
10288 Local<Value> value,
10289 const v8::PropertyCallbackInfo<void>& info) {
10290 info.This()->ForceSet(name, value);
10294 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
10295 v8::HandleScope scope(v8::Isolate::GetCurrent());
10296 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10297 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10298 templ->SetAccessor(v8_str("y"), Return239Callback);
10299 LocalContext context;
10300 context->Global()->Set(v8_str("o"), templ->NewInstance());
10302 // Check the case when receiver and interceptor's holder
10303 // are the same objects.
10304 v8::Handle<Value> value = CompileRun(
10306 "for (var i = 0; i < 7; i++) {"
10309 CHECK_EQ(239, value->Int32Value());
10311 // Check the case when interceptor's holder is in proto chain
10313 value = CompileRun(
10314 "r = { __proto__: o };"
10316 "for (var i = 0; i < 7; i++) {"
10319 CHECK_EQ(239, value->Int32Value());
10323 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
10324 v8::HandleScope scope(v8::Isolate::GetCurrent());
10325 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10326 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10327 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10328 templ_p->SetAccessor(v8_str("y"), Return239Callback);
10330 LocalContext context;
10331 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10332 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10334 // Check the case when receiver and interceptor's holder
10335 // are the same objects.
10336 v8::Handle<Value> value = CompileRun(
10339 "for (var i = 0; i < 7; i++) {"
10340 " result = o.x + o.y;"
10342 CHECK_EQ(239 + 42, value->Int32Value());
10344 // Check the case when interceptor's holder is in proto chain
10346 value = CompileRun(
10347 "r = { __proto__: o };"
10349 "for (var i = 0; i < 7; i++) {"
10350 " result = r.x + r.y;"
10352 CHECK_EQ(239 + 42, value->Int32Value());
10356 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
10357 v8::HandleScope scope(v8::Isolate::GetCurrent());
10358 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10359 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10360 templ->SetAccessor(v8_str("y"), Return239Callback);
10362 LocalContext context;
10363 context->Global()->Set(v8_str("o"), templ->NewInstance());
10365 v8::Handle<Value> value = CompileRun(
10366 "fst = new Object(); fst.__proto__ = o;"
10367 "snd = new Object(); snd.__proto__ = fst;"
10369 "for (var i = 0; i < 7; i++) {"
10370 " result1 = snd.x;"
10374 "for (var i = 0; i < 7; i++) {"
10377 "result + result1");
10378 CHECK_EQ(239 + 42, value->Int32Value());
10382 // Test the case when we stored callback into
10383 // a stub, but interceptor produced value on its own.
10384 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
10385 v8::HandleScope scope(v8::Isolate::GetCurrent());
10386 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10387 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10388 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10389 templ_p->SetAccessor(v8_str("y"), Return239Callback);
10391 LocalContext context;
10392 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10393 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10395 v8::Handle<Value> value = CompileRun(
10397 "for (var i = 0; i < 7; i++) {"
10399 // Now it should be ICed and keep a reference to x defined on p
10402 "for (var i = 0; i < 7; i++) {"
10406 CHECK_EQ(42 * 7, value->Int32Value());
10410 // Test the case when we stored callback into
10411 // a stub, but it got invalidated later on.
10412 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
10413 v8::HandleScope scope(v8::Isolate::GetCurrent());
10414 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10415 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10416 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10417 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
10419 LocalContext context;
10420 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10421 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10423 v8::Handle<Value> value = CompileRun(
10424 "inbetween = new Object();"
10425 "o.__proto__ = inbetween;"
10426 "inbetween.__proto__ = p;"
10427 "for (var i = 0; i < 10; i++) {"
10429 // Now it should be ICed and keep a reference to y defined on p
10431 "inbetween.y = 42;"
10433 "for (var i = 0; i < 10; i++) {"
10437 CHECK_EQ(42 * 10, value->Int32Value());
10441 // Test the case when we stored callback into
10442 // a stub, but it got invalidated later on due to override on
10443 // global object which is between interceptor and callbacks' holders.
10444 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
10445 v8::HandleScope scope(v8::Isolate::GetCurrent());
10446 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10447 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10448 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New();
10449 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
10451 LocalContext context;
10452 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10453 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
10455 v8::Handle<Value> value = CompileRun(
10456 "o.__proto__ = this;"
10457 "this.__proto__ = p;"
10458 "for (var i = 0; i < 10; i++) {"
10459 " if (o.y != 239) throw 'oops: ' + o.y;"
10460 // Now it should be ICed and keep a reference to y defined on p
10464 "for (var i = 0; i < 10; i++) {"
10468 CHECK_EQ(42 * 10, value->Int32Value());
10472 static void InterceptorLoadICGetter0(
10473 Local<String> name,
10474 const v8::PropertyCallbackInfo<v8::Value>& info) {
10475 ApiTestFuzzer::Fuzz();
10476 CHECK(v8_str("x")->Equals(name));
10477 info.GetReturnValue().Set(v8::Integer::New(0));
10481 THREADED_TEST(InterceptorReturningZero) {
10482 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
10483 "o.x == undefined ? 1 : 0",
10488 static void InterceptorStoreICSetter(
10490 Local<Value> value,
10491 const v8::PropertyCallbackInfo<v8::Value>& info) {
10492 CHECK(v8_str("x")->Equals(key));
10493 CHECK_EQ(42, value->Int32Value());
10494 info.GetReturnValue().Set(value);
10498 // This test should hit the store IC for the interceptor case.
10499 THREADED_TEST(InterceptorStoreIC) {
10500 v8::HandleScope scope(v8::Isolate::GetCurrent());
10501 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10502 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
10503 InterceptorStoreICSetter,
10504 0, 0, 0, v8_str("data"));
10505 LocalContext context;
10506 context->Global()->Set(v8_str("o"), templ->NewInstance());
10508 "for (var i = 0; i < 1000; i++) {"
10514 THREADED_TEST(InterceptorStoreICWithNoSetter) {
10515 v8::HandleScope scope(v8::Isolate::GetCurrent());
10516 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10517 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
10518 LocalContext context;
10519 context->Global()->Set(v8_str("o"), templ->NewInstance());
10520 v8::Handle<Value> value = CompileRun(
10521 "for (var i = 0; i < 1000; i++) {"
10525 CHECK_EQ(239 + 42, value->Int32Value());
10531 v8::Handle<Value> call_ic_function;
10532 v8::Handle<Value> call_ic_function2;
10533 v8::Handle<Value> call_ic_function3;
10535 static void InterceptorCallICGetter(
10536 Local<String> name,
10537 const v8::PropertyCallbackInfo<v8::Value>& info) {
10538 ApiTestFuzzer::Fuzz();
10539 CHECK(v8_str("x")->Equals(name));
10540 info.GetReturnValue().Set(call_ic_function);
10544 // This test should hit the call IC for the interceptor case.
10545 THREADED_TEST(InterceptorCallIC) {
10546 v8::HandleScope scope(v8::Isolate::GetCurrent());
10547 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10548 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
10549 LocalContext context;
10550 context->Global()->Set(v8_str("o"), templ->NewInstance());
10552 v8_compile("function f(x) { return x + 1; }; f")->Run();
10553 v8::Handle<Value> value = CompileRun(
10555 "for (var i = 0; i < 1000; i++) {"
10556 " result = o.x(41);"
10558 CHECK_EQ(42, value->Int32Value());
10562 // This test checks that if interceptor doesn't provide
10563 // a value, we can fetch regular value.
10564 THREADED_TEST(InterceptorCallICSeesOthers) {
10565 v8::HandleScope scope(v8::Isolate::GetCurrent());
10566 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10567 templ->SetNamedPropertyHandler(NoBlockGetterX);
10568 LocalContext context;
10569 context->Global()->Set(v8_str("o"), templ->NewInstance());
10570 v8::Handle<Value> value = CompileRun(
10571 "o.x = function f(x) { return x + 1; };"
10573 "for (var i = 0; i < 7; i++) {"
10574 " result = o.x(41);"
10576 CHECK_EQ(42, value->Int32Value());
10580 static v8::Handle<Value> call_ic_function4;
10581 static void InterceptorCallICGetter4(
10582 Local<String> name,
10583 const v8::PropertyCallbackInfo<v8::Value>& info) {
10584 ApiTestFuzzer::Fuzz();
10585 CHECK(v8_str("x")->Equals(name));
10586 info.GetReturnValue().Set(call_ic_function4);
10590 // This test checks that if interceptor provides a function,
10591 // even if we cached shadowed variant, interceptor's function
10593 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
10594 v8::HandleScope scope(v8::Isolate::GetCurrent());
10595 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10596 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
10597 LocalContext context;
10598 context->Global()->Set(v8_str("o"), templ->NewInstance());
10599 call_ic_function4 =
10600 v8_compile("function f(x) { return x - 1; }; f")->Run();
10601 v8::Handle<Value> value = CompileRun(
10602 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
10604 "for (var i = 0; i < 1000; i++) {"
10605 " result = o.x(42);"
10607 CHECK_EQ(41, value->Int32Value());
10611 // Test the case when we stored cacheable lookup into
10612 // a stub, but it got invalidated later on
10613 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
10614 v8::HandleScope scope(v8::Isolate::GetCurrent());
10615 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10616 templ->SetNamedPropertyHandler(NoBlockGetterX);
10617 LocalContext context;
10618 context->Global()->Set(v8_str("o"), templ->NewInstance());
10619 v8::Handle<Value> value = CompileRun(
10620 "proto1 = new Object();"
10621 "proto2 = new Object();"
10622 "o.__proto__ = proto1;"
10623 "proto1.__proto__ = proto2;"
10624 "proto2.y = function(x) { return x + 1; };"
10625 // Invoke it many times to compile a stub
10626 "for (var i = 0; i < 7; i++) {"
10629 "proto1.y = function(x) { return x - 1; };"
10631 "for (var i = 0; i < 7; i++) {"
10632 " result += o.y(42);"
10634 CHECK_EQ(41 * 7, value->Int32Value());
10638 // This test checks that if interceptor doesn't provide a function,
10639 // cached constant function is used
10640 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
10641 v8::HandleScope scope(v8::Isolate::GetCurrent());
10642 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10643 templ->SetNamedPropertyHandler(NoBlockGetterX);
10644 LocalContext context;
10645 context->Global()->Set(v8_str("o"), templ->NewInstance());
10646 v8::Handle<Value> value = CompileRun(
10647 "function inc(x) { return x + 1; };"
10651 "for (var i = 0; i < 1000; i++) {"
10652 " result = o.x(42);"
10654 CHECK_EQ(43, value->Int32Value());
10658 static v8::Handle<Value> call_ic_function5;
10659 static void InterceptorCallICGetter5(
10660 Local<String> name,
10661 const v8::PropertyCallbackInfo<v8::Value>& info) {
10662 ApiTestFuzzer::Fuzz();
10663 if (v8_str("x")->Equals(name))
10664 info.GetReturnValue().Set(call_ic_function5);
10668 // This test checks that if interceptor provides a function,
10669 // even if we cached constant function, interceptor's function
10671 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
10672 v8::HandleScope scope(v8::Isolate::GetCurrent());
10673 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10674 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
10675 LocalContext context;
10676 context->Global()->Set(v8_str("o"), templ->NewInstance());
10677 call_ic_function5 =
10678 v8_compile("function f(x) { return x - 1; }; f")->Run();
10679 v8::Handle<Value> value = CompileRun(
10680 "function inc(x) { return x + 1; };"
10684 "for (var i = 0; i < 1000; i++) {"
10685 " result = o.x(42);"
10687 CHECK_EQ(41, value->Int32Value());
10691 static v8::Handle<Value> call_ic_function6;
10692 static void InterceptorCallICGetter6(
10693 Local<String> name,
10694 const v8::PropertyCallbackInfo<v8::Value>& info) {
10695 ApiTestFuzzer::Fuzz();
10696 if (v8_str("x")->Equals(name))
10697 info.GetReturnValue().Set(call_ic_function6);
10701 // Same test as above, except the code is wrapped in a function
10702 // to test the optimized compiler.
10703 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
10704 i::FLAG_allow_natives_syntax = true;
10705 v8::HandleScope scope(v8::Isolate::GetCurrent());
10706 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10707 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
10708 LocalContext context;
10709 context->Global()->Set(v8_str("o"), templ->NewInstance());
10710 call_ic_function6 =
10711 v8_compile("function f(x) { return x - 1; }; f")->Run();
10712 v8::Handle<Value> value = CompileRun(
10713 "function inc(x) { return x + 1; };"
10716 "function test() {"
10718 " for (var i = 0; i < 1000; i++) {"
10719 " result = o.x(42);"
10726 "%OptimizeFunctionOnNextCall(test);"
10728 CHECK_EQ(41, value->Int32Value());
10732 // Test the case when we stored constant function into
10733 // a stub, but it got invalidated later on
10734 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
10735 v8::HandleScope scope(v8::Isolate::GetCurrent());
10736 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10737 templ->SetNamedPropertyHandler(NoBlockGetterX);
10738 LocalContext context;
10739 context->Global()->Set(v8_str("o"), templ->NewInstance());
10740 v8::Handle<Value> value = CompileRun(
10741 "function inc(x) { return x + 1; };"
10743 "proto1 = new Object();"
10744 "proto2 = new Object();"
10745 "o.__proto__ = proto1;"
10746 "proto1.__proto__ = proto2;"
10748 // Invoke it many times to compile a stub
10749 "for (var i = 0; i < 7; i++) {"
10752 "proto1.y = function(x) { return x - 1; };"
10754 "for (var i = 0; i < 7; i++) {"
10755 " result += o.y(42);"
10757 CHECK_EQ(41 * 7, value->Int32Value());
10761 // Test the case when we stored constant function into
10762 // a stub, but it got invalidated later on due to override on
10763 // global object which is between interceptor and constant function' holders.
10764 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
10765 v8::HandleScope scope(v8::Isolate::GetCurrent());
10766 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
10767 templ->SetNamedPropertyHandler(NoBlockGetterX);
10768 LocalContext context;
10769 context->Global()->Set(v8_str("o"), templ->NewInstance());
10770 v8::Handle<Value> value = CompileRun(
10771 "function inc(x) { return x + 1; };"
10773 "o.__proto__ = this;"
10774 "this.__proto__.y = inc;"
10775 // Invoke it many times to compile a stub
10776 "for (var i = 0; i < 7; i++) {"
10777 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
10779 "this.y = function(x) { return x - 1; };"
10781 "for (var i = 0; i < 7; i++) {"
10782 " result += o.y(42);"
10784 CHECK_EQ(41 * 7, value->Int32Value());
10788 // Test the case when actual function to call sits on global object.
10789 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
10790 v8::HandleScope scope(v8::Isolate::GetCurrent());
10791 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
10792 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
10794 LocalContext context;
10795 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
10797 v8::Handle<Value> value = CompileRun(
10799 " o.__proto__ = this;"
10800 " for (var i = 0; i < 10; i++) {"
10801 " var v = o.parseFloat('239');"
10802 " if (v != 239) throw v;"
10803 // Now it should be ICed and keep a reference to parseFloat.
10806 " for (var i = 0; i < 10; i++) {"
10807 " result += o.parseFloat('239');"
10813 CHECK_EQ(239 * 10, value->Int32Value());
10816 static void InterceptorCallICFastApi(
10817 Local<String> name,
10818 const v8::PropertyCallbackInfo<v8::Value>& info) {
10819 ApiTestFuzzer::Fuzz();
10820 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
10822 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
10824 if ((*call_count) % 20 == 0) {
10825 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
10829 static void FastApiCallback_TrivialSignature(
10830 const v8::FunctionCallbackInfo<v8::Value>& args) {
10831 ApiTestFuzzer::Fuzz();
10832 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
10833 v8::Isolate* isolate = v8::Isolate::GetCurrent();
10834 CHECK_EQ(isolate, args.GetIsolate());
10835 CHECK_EQ(args.This(), args.Holder());
10836 CHECK(args.Data()->Equals(v8_str("method_data")));
10837 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10840 static void FastApiCallback_SimpleSignature(
10841 const v8::FunctionCallbackInfo<v8::Value>& args) {
10842 ApiTestFuzzer::Fuzz();
10843 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
10844 v8::Isolate* isolate = v8::Isolate::GetCurrent();
10845 CHECK_EQ(isolate, args.GetIsolate());
10846 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
10847 CHECK(args.Data()->Equals(v8_str("method_data")));
10848 // Note, we're using HasRealNamedProperty instead of Has to avoid
10849 // invoking the interceptor again.
10850 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
10851 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10855 // Helper to maximize the odds of object moving.
10856 static void GenerateSomeGarbage() {
10859 "for (var i = 0; i < 1000; i++) {"
10860 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
10862 "garbage = undefined;");
10866 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
10867 static int count = 0;
10868 if (count++ % 3 == 0) {
10869 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
10870 // This should move the stub
10871 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
10876 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
10877 LocalContext context;
10878 v8::HandleScope scope(context->GetIsolate());
10879 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
10880 nativeobject_templ->Set("callback",
10881 v8::FunctionTemplate::New(DirectApiCallback));
10882 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10883 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10884 // call the api function multiple times to ensure direct call stub creation.
10887 " for (var i = 1; i <= 30; i++) {"
10888 " nativeobject.callback();"
10895 void ThrowingDirectApiCallback(
10896 const v8::FunctionCallbackInfo<v8::Value>& args) {
10897 v8::ThrowException(v8_str("g"));
10901 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
10902 LocalContext context;
10903 v8::HandleScope scope(context->GetIsolate());
10904 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New();
10905 nativeobject_templ->Set("callback",
10906 v8::FunctionTemplate::New(ThrowingDirectApiCallback));
10907 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10908 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10909 // call the api function multiple times to ensure direct call stub creation.
10910 v8::Handle<Value> result = CompileRun(
10913 " for (var i = 1; i <= 5; i++) {"
10914 " try { nativeobject.callback(); } catch (e) { result += e; }"
10918 CHECK_EQ(v8_str("ggggg"), result);
10922 static Handle<Value> DoDirectGetter() {
10923 if (++p_getter_count % 3 == 0) {
10924 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
10925 GenerateSomeGarbage();
10927 return v8_str("Direct Getter Result");
10930 static void DirectGetterCallback(
10931 Local<String> name,
10932 const v8::PropertyCallbackInfo<v8::Value>& info) {
10933 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
10934 info.GetReturnValue().Set(DoDirectGetter());
10938 template<typename Accessor>
10939 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
10940 LocalContext context;
10941 v8::HandleScope scope(context->GetIsolate());
10942 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
10943 obj->SetAccessor(v8_str("p1"), accessor);
10944 context->Global()->Set(v8_str("o1"), obj->NewInstance());
10945 p_getter_count = 0;
10946 v8::Handle<v8::Value> result = CompileRun(
10948 " for (var i = 0; i < 30; i++) o1.p1;"
10952 CHECK_EQ(v8_str("Direct Getter Result"), result);
10953 CHECK_EQ(31, p_getter_count);
10957 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
10958 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
10962 void ThrowingDirectGetterCallback(
10963 Local<String> name,
10964 const v8::PropertyCallbackInfo<v8::Value>& info) {
10965 v8::ThrowException(v8_str("g"));
10969 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
10970 LocalContext context;
10971 v8::HandleScope scope(context->GetIsolate());
10972 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New();
10973 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
10974 context->Global()->Set(v8_str("o1"), obj->NewInstance());
10975 v8::Handle<Value> result = CompileRun(
10977 "for (var i = 0; i < 5; i++) {"
10978 " try { o1.p1; } catch (e) { result += e; }"
10981 CHECK_EQ(v8_str("ggggg"), result);
10985 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
10986 int interceptor_call_count = 0;
10987 v8::HandleScope scope(v8::Isolate::GetCurrent());
10988 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
10989 v8::Handle<v8::FunctionTemplate> method_templ =
10990 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
10991 v8_str("method_data"),
10992 v8::Handle<v8::Signature>());
10993 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10994 proto_templ->Set(v8_str("method"), method_templ);
10995 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10996 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
10997 NULL, NULL, NULL, NULL,
10998 v8::External::New(&interceptor_call_count));
10999 LocalContext context;
11000 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11001 GenerateSomeGarbage();
11002 context->Global()->Set(v8_str("o"), fun->NewInstance());
11005 "for (var i = 0; i < 100; i++) {"
11006 " result = o.method(41);"
11008 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11009 CHECK_EQ(100, interceptor_call_count);
11013 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
11014 int interceptor_call_count = 0;
11015 v8::HandleScope scope(v8::Isolate::GetCurrent());
11016 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11017 v8::Handle<v8::FunctionTemplate> method_templ =
11018 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11019 v8_str("method_data"),
11020 v8::Signature::New(fun_templ));
11021 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11022 proto_templ->Set(v8_str("method"), method_templ);
11023 fun_templ->SetHiddenPrototype(true);
11024 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11025 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11026 NULL, NULL, NULL, NULL,
11027 v8::External::New(&interceptor_call_count));
11028 LocalContext context;
11029 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11030 GenerateSomeGarbage();
11031 context->Global()->Set(v8_str("o"), fun->NewInstance());
11034 "var receiver = {};"
11035 "receiver.__proto__ = o;"
11037 "for (var i = 0; i < 100; i++) {"
11038 " result = receiver.method(41);"
11040 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11041 CHECK_EQ(100, interceptor_call_count);
11045 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
11046 int interceptor_call_count = 0;
11047 v8::HandleScope scope(v8::Isolate::GetCurrent());
11048 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11049 v8::Handle<v8::FunctionTemplate> method_templ =
11050 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11051 v8_str("method_data"),
11052 v8::Signature::New(fun_templ));
11053 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11054 proto_templ->Set(v8_str("method"), method_templ);
11055 fun_templ->SetHiddenPrototype(true);
11056 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11057 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11058 NULL, NULL, NULL, NULL,
11059 v8::External::New(&interceptor_call_count));
11060 LocalContext context;
11061 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11062 GenerateSomeGarbage();
11063 context->Global()->Set(v8_str("o"), fun->NewInstance());
11066 "var receiver = {};"
11067 "receiver.__proto__ = o;"
11069 "var saved_result = 0;"
11070 "for (var i = 0; i < 100; i++) {"
11071 " result = receiver.method(41);"
11073 " saved_result = result;"
11074 " receiver = {method: function(x) { return x - 1 }};"
11077 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11078 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11079 CHECK_GE(interceptor_call_count, 50);
11083 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
11084 int interceptor_call_count = 0;
11085 v8::HandleScope scope(v8::Isolate::GetCurrent());
11086 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11087 v8::Handle<v8::FunctionTemplate> method_templ =
11088 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11089 v8_str("method_data"),
11090 v8::Signature::New(fun_templ));
11091 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11092 proto_templ->Set(v8_str("method"), method_templ);
11093 fun_templ->SetHiddenPrototype(true);
11094 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11095 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11096 NULL, NULL, NULL, NULL,
11097 v8::External::New(&interceptor_call_count));
11098 LocalContext context;
11099 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11100 GenerateSomeGarbage();
11101 context->Global()->Set(v8_str("o"), fun->NewInstance());
11104 "var receiver = {};"
11105 "receiver.__proto__ = o;"
11107 "var saved_result = 0;"
11108 "for (var i = 0; i < 100; i++) {"
11109 " result = receiver.method(41);"
11111 " saved_result = result;"
11112 " o.method = function(x) { return x - 1 };"
11115 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11116 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11117 CHECK_GE(interceptor_call_count, 50);
11121 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
11122 int interceptor_call_count = 0;
11123 v8::HandleScope scope(v8::Isolate::GetCurrent());
11124 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11125 v8::Handle<v8::FunctionTemplate> method_templ =
11126 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11127 v8_str("method_data"),
11128 v8::Signature::New(fun_templ));
11129 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11130 proto_templ->Set(v8_str("method"), method_templ);
11131 fun_templ->SetHiddenPrototype(true);
11132 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11133 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11134 NULL, NULL, NULL, NULL,
11135 v8::External::New(&interceptor_call_count));
11136 LocalContext context;
11137 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11138 GenerateSomeGarbage();
11139 context->Global()->Set(v8_str("o"), fun->NewInstance());
11140 v8::TryCatch try_catch;
11143 "var receiver = {};"
11144 "receiver.__proto__ = o;"
11146 "var saved_result = 0;"
11147 "for (var i = 0; i < 100; i++) {"
11148 " result = receiver.method(41);"
11150 " saved_result = result;"
11154 CHECK(try_catch.HasCaught());
11155 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
11156 try_catch.Exception()->ToString());
11157 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11158 CHECK_GE(interceptor_call_count, 50);
11162 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
11163 int interceptor_call_count = 0;
11164 v8::HandleScope scope(v8::Isolate::GetCurrent());
11165 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11166 v8::Handle<v8::FunctionTemplate> method_templ =
11167 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11168 v8_str("method_data"),
11169 v8::Signature::New(fun_templ));
11170 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11171 proto_templ->Set(v8_str("method"), method_templ);
11172 fun_templ->SetHiddenPrototype(true);
11173 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
11174 templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
11175 NULL, NULL, NULL, NULL,
11176 v8::External::New(&interceptor_call_count));
11177 LocalContext context;
11178 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11179 GenerateSomeGarbage();
11180 context->Global()->Set(v8_str("o"), fun->NewInstance());
11181 v8::TryCatch try_catch;
11184 "var receiver = {};"
11185 "receiver.__proto__ = o;"
11187 "var saved_result = 0;"
11188 "for (var i = 0; i < 100; i++) {"
11189 " result = receiver.method(41);"
11191 " saved_result = result;"
11192 " receiver = {method: receiver.method};"
11195 CHECK(try_catch.HasCaught());
11196 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
11197 try_catch.Exception()->ToString());
11198 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11199 CHECK_GE(interceptor_call_count, 50);
11203 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
11204 v8::HandleScope scope(v8::Isolate::GetCurrent());
11205 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11206 v8::Handle<v8::FunctionTemplate> method_templ =
11207 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature,
11208 v8_str("method_data"),
11209 v8::Handle<v8::Signature>());
11210 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11211 proto_templ->Set(v8_str("method"), method_templ);
11212 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11214 LocalContext context;
11215 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11216 GenerateSomeGarbage();
11217 context->Global()->Set(v8_str("o"), fun->NewInstance());
11220 "for (var i = 0; i < 100; i++) {"
11221 " result = o.method(41);"
11224 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11228 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
11229 v8::HandleScope scope(v8::Isolate::GetCurrent());
11230 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11231 v8::Handle<v8::FunctionTemplate> method_templ =
11232 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11233 v8_str("method_data"),
11234 v8::Signature::New(fun_templ));
11235 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11236 proto_templ->Set(v8_str("method"), method_templ);
11237 fun_templ->SetHiddenPrototype(true);
11238 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11239 CHECK(!templ.IsEmpty());
11240 LocalContext context;
11241 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11242 GenerateSomeGarbage();
11243 context->Global()->Set(v8_str("o"), fun->NewInstance());
11246 "var receiver = {};"
11247 "receiver.__proto__ = o;"
11249 "for (var i = 0; i < 100; i++) {"
11250 " result = receiver.method(41);"
11253 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
11257 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
11258 v8::HandleScope scope(v8::Isolate::GetCurrent());
11259 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11260 v8::Handle<v8::FunctionTemplate> method_templ =
11261 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11262 v8_str("method_data"),
11263 v8::Signature::New(fun_templ));
11264 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11265 proto_templ->Set(v8_str("method"), method_templ);
11266 fun_templ->SetHiddenPrototype(true);
11267 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11268 CHECK(!templ.IsEmpty());
11269 LocalContext context;
11270 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11271 GenerateSomeGarbage();
11272 context->Global()->Set(v8_str("o"), fun->NewInstance());
11275 "var receiver = {};"
11276 "receiver.__proto__ = o;"
11278 "var saved_result = 0;"
11279 "for (var i = 0; i < 100; i++) {"
11280 " result = receiver.method(41);"
11282 " saved_result = result;"
11283 " receiver = {method: function(x) { return x - 1 }};"
11286 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
11287 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11291 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
11292 v8::HandleScope scope(v8::Isolate::GetCurrent());
11293 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11294 v8::Handle<v8::FunctionTemplate> method_templ =
11295 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11296 v8_str("method_data"),
11297 v8::Signature::New(fun_templ));
11298 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11299 proto_templ->Set(v8_str("method"), method_templ);
11300 fun_templ->SetHiddenPrototype(true);
11301 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11302 CHECK(!templ.IsEmpty());
11303 LocalContext context;
11304 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11305 GenerateSomeGarbage();
11306 context->Global()->Set(v8_str("o"), fun->NewInstance());
11307 v8::TryCatch try_catch;
11310 "var receiver = {};"
11311 "receiver.__proto__ = o;"
11313 "var saved_result = 0;"
11314 "for (var i = 0; i < 100; i++) {"
11315 " result = receiver.method(41);"
11317 " saved_result = result;"
11321 CHECK(try_catch.HasCaught());
11322 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"),
11323 try_catch.Exception()->ToString());
11324 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11328 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
11329 v8::HandleScope scope(v8::Isolate::GetCurrent());
11330 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
11331 v8::Handle<v8::FunctionTemplate> method_templ =
11332 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
11333 v8_str("method_data"),
11334 v8::Signature::New(fun_templ));
11335 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
11336 proto_templ->Set(v8_str("method"), method_templ);
11337 fun_templ->SetHiddenPrototype(true);
11338 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
11339 CHECK(!templ.IsEmpty());
11340 LocalContext context;
11341 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
11342 GenerateSomeGarbage();
11343 context->Global()->Set(v8_str("o"), fun->NewInstance());
11344 v8::TryCatch try_catch;
11347 "var receiver = {};"
11348 "receiver.__proto__ = o;"
11350 "var saved_result = 0;"
11351 "for (var i = 0; i < 100; i++) {"
11352 " result = receiver.method(41);"
11354 " saved_result = result;"
11355 " receiver = Object.create(receiver);"
11358 CHECK(try_catch.HasCaught());
11359 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
11360 try_catch.Exception()->ToString());
11361 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11365 v8::Handle<Value> keyed_call_ic_function;
11367 static void InterceptorKeyedCallICGetter(
11368 Local<String> name,
11369 const v8::PropertyCallbackInfo<v8::Value>& info) {
11370 ApiTestFuzzer::Fuzz();
11371 if (v8_str("x")->Equals(name)) {
11372 info.GetReturnValue().Set(keyed_call_ic_function);
11377 // Test the case when we stored cacheable lookup into
11378 // a stub, but the function name changed (to another cacheable function).
11379 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
11380 v8::HandleScope scope(v8::Isolate::GetCurrent());
11381 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11382 templ->SetNamedPropertyHandler(NoBlockGetterX);
11383 LocalContext context;
11384 context->Global()->Set(v8_str("o"), templ->NewInstance());
11386 "proto = new Object();"
11387 "proto.y = function(x) { return x + 1; };"
11388 "proto.z = function(x) { return x - 1; };"
11389 "o.__proto__ = proto;"
11391 "var method = 'y';"
11392 "for (var i = 0; i < 10; i++) {"
11393 " if (i == 5) { method = 'z'; };"
11394 " result += o[method](41);"
11396 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11400 // Test the case when we stored cacheable lookup into
11401 // a stub, but the function name changed (and the new function is present
11402 // both before and after the interceptor in the prototype chain).
11403 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
11404 v8::HandleScope scope(v8::Isolate::GetCurrent());
11405 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11406 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
11407 LocalContext context;
11408 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
11409 keyed_call_ic_function =
11410 v8_compile("function f(x) { return x - 1; }; f")->Run();
11412 "o = new Object();"
11413 "proto2 = new Object();"
11414 "o.y = function(x) { return x + 1; };"
11415 "proto2.y = function(x) { return x + 2; };"
11416 "o.__proto__ = proto1;"
11417 "proto1.__proto__ = proto2;"
11419 "var method = 'x';"
11420 "for (var i = 0; i < 10; i++) {"
11421 " if (i == 5) { method = 'y'; };"
11422 " result += o[method](41);"
11424 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11428 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
11429 // on the global object.
11430 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
11431 v8::HandleScope scope(v8::Isolate::GetCurrent());
11432 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11433 templ->SetNamedPropertyHandler(NoBlockGetterX);
11434 LocalContext context;
11435 context->Global()->Set(v8_str("o"), templ->NewInstance());
11437 "function inc(x) { return x + 1; };"
11439 "function dec(x) { return x - 1; };"
11441 "o.__proto__ = this;"
11442 "this.__proto__.x = inc;"
11443 "this.__proto__.y = dec;"
11445 "var method = 'x';"
11446 "for (var i = 0; i < 10; i++) {"
11447 " if (i == 5) { method = 'y'; };"
11448 " result += o[method](41);"
11450 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11454 // Test the case when actual function to call sits on global object.
11455 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
11456 v8::HandleScope scope(v8::Isolate::GetCurrent());
11457 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11458 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11459 LocalContext context;
11460 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11463 "function len(x) { return x.length; };"
11464 "o.__proto__ = this;"
11465 "var m = 'parseFloat';"
11467 "for (var i = 0; i < 10; i++) {"
11470 " saved_result = result;"
11472 " result = o[m]('239');"
11474 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
11475 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
11479 // Test the map transition before the interceptor.
11480 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
11481 v8::HandleScope scope(v8::Isolate::GetCurrent());
11482 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11483 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11484 LocalContext context;
11485 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
11488 "var o = new Object();"
11489 "o.__proto__ = proto;"
11490 "o.method = function(x) { return x + 1; };"
11491 "var m = 'method';"
11493 "for (var i = 0; i < 10; i++) {"
11494 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
11495 " result += o[m](41);"
11497 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11501 // Test the map transition after the interceptor.
11502 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
11503 v8::HandleScope scope(v8::Isolate::GetCurrent());
11504 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
11505 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
11506 LocalContext context;
11507 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11510 "var proto = new Object();"
11511 "o.__proto__ = proto;"
11512 "proto.method = function(x) { return x + 1; };"
11513 "var m = 'method';"
11515 "for (var i = 0; i < 10; i++) {"
11516 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
11517 " result += o[m](41);"
11519 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
11523 static int interceptor_call_count = 0;
11525 static void InterceptorICRefErrorGetter(
11526 Local<String> name,
11527 const v8::PropertyCallbackInfo<v8::Value>& info) {
11528 ApiTestFuzzer::Fuzz();
11529 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
11530 info.GetReturnValue().Set(call_ic_function2);
11535 // This test should hit load and call ICs for the interceptor case.
11536 // Once in a while, the interceptor will reply that a property was not
11537 // found in which case we should get a reference error.
11538 THREADED_TEST(InterceptorICReferenceErrors) {
11539 v8::HandleScope scope(v8::Isolate::GetCurrent());
11540 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11541 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
11542 LocalContext context(0, templ, v8::Handle<Value>());
11543 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
11544 v8::Handle<Value> value = CompileRun(
11546 " for (var i = 0; i < 1000; i++) {"
11547 " try { x; } catch(e) { return true; }"
11552 CHECK_EQ(true, value->BooleanValue());
11553 interceptor_call_count = 0;
11554 value = CompileRun(
11556 " for (var i = 0; i < 1000; i++) {"
11557 " try { x(42); } catch(e) { return true; }"
11562 CHECK_EQ(true, value->BooleanValue());
11566 static int interceptor_ic_exception_get_count = 0;
11568 static void InterceptorICExceptionGetter(
11569 Local<String> name,
11570 const v8::PropertyCallbackInfo<v8::Value>& info) {
11571 ApiTestFuzzer::Fuzz();
11572 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
11573 info.GetReturnValue().Set(call_ic_function3);
11575 if (interceptor_ic_exception_get_count == 20) {
11576 v8::ThrowException(v8_num(42));
11582 // Test interceptor load/call IC where the interceptor throws an
11583 // exception once in a while.
11584 THREADED_TEST(InterceptorICGetterExceptions) {
11585 interceptor_ic_exception_get_count = 0;
11586 v8::HandleScope scope(v8::Isolate::GetCurrent());
11587 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11588 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
11589 LocalContext context(0, templ, v8::Handle<Value>());
11590 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
11591 v8::Handle<Value> value = CompileRun(
11593 " for (var i = 0; i < 100; i++) {"
11594 " try { x; } catch(e) { return true; }"
11599 CHECK_EQ(true, value->BooleanValue());
11600 interceptor_ic_exception_get_count = 0;
11601 value = CompileRun(
11603 " for (var i = 0; i < 100; i++) {"
11604 " try { x(42); } catch(e) { return true; }"
11609 CHECK_EQ(true, value->BooleanValue());
11613 static int interceptor_ic_exception_set_count = 0;
11615 static void InterceptorICExceptionSetter(
11617 Local<Value> value,
11618 const v8::PropertyCallbackInfo<v8::Value>& info) {
11619 ApiTestFuzzer::Fuzz();
11620 if (++interceptor_ic_exception_set_count > 20) {
11621 v8::ThrowException(v8_num(42));
11626 // Test interceptor store IC where the interceptor throws an exception
11627 // once in a while.
11628 THREADED_TEST(InterceptorICSetterExceptions) {
11629 interceptor_ic_exception_set_count = 0;
11630 v8::HandleScope scope(v8::Isolate::GetCurrent());
11631 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11632 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
11633 LocalContext context(0, templ, v8::Handle<Value>());
11634 v8::Handle<Value> value = CompileRun(
11636 " for (var i = 0; i < 100; i++) {"
11637 " try { x = 42; } catch(e) { return true; }"
11642 CHECK_EQ(true, value->BooleanValue());
11646 // Test that we ignore null interceptors.
11647 THREADED_TEST(NullNamedInterceptor) {
11648 v8::HandleScope scope(v8::Isolate::GetCurrent());
11649 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11650 templ->SetNamedPropertyHandler(
11651 static_cast<v8::NamedPropertyGetterCallback>(0));
11652 LocalContext context;
11653 templ->Set("x", v8_num(42));
11654 v8::Handle<v8::Object> obj = templ->NewInstance();
11655 context->Global()->Set(v8_str("obj"), obj);
11656 v8::Handle<Value> value = CompileRun("obj.x");
11657 CHECK(value->IsInt32());
11658 CHECK_EQ(42, value->Int32Value());
11662 // Test that we ignore null interceptors.
11663 THREADED_TEST(NullIndexedInterceptor) {
11664 v8::HandleScope scope(v8::Isolate::GetCurrent());
11665 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
11666 templ->SetIndexedPropertyHandler(
11667 static_cast<v8::IndexedPropertyGetterCallback>(0));
11668 LocalContext context;
11669 templ->Set("42", v8_num(42));
11670 v8::Handle<v8::Object> obj = templ->NewInstance();
11671 context->Global()->Set(v8_str("obj"), obj);
11672 v8::Handle<Value> value = CompileRun("obj[42]");
11673 CHECK(value->IsInt32());
11674 CHECK_EQ(42, value->Int32Value());
11678 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
11679 v8::HandleScope scope(v8::Isolate::GetCurrent());
11680 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
11681 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11683 env->Global()->Set(v8_str("obj"),
11684 templ->GetFunction()->NewInstance());
11685 ExpectTrue("obj.x === 42");
11686 ExpectTrue("!obj.propertyIsEnumerable('x')");
11690 static void ThrowingGetter(Local<String> name,
11691 const v8::PropertyCallbackInfo<v8::Value>& info) {
11692 ApiTestFuzzer::Fuzz();
11693 ThrowException(Handle<Value>());
11694 info.GetReturnValue().SetUndefined();
11698 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
11699 LocalContext context;
11700 HandleScope scope(context->GetIsolate());
11702 Local<FunctionTemplate> templ = FunctionTemplate::New();
11703 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
11704 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
11706 Local<Object> instance = templ->GetFunction()->NewInstance();
11708 Local<Object> another = Object::New();
11709 another->SetPrototype(instance);
11711 Local<Object> with_js_getter = CompileRun(
11713 "o.__defineGetter__('f', function() { throw undefined; });\n"
11714 "o\n").As<Object>();
11715 CHECK(!with_js_getter.IsEmpty());
11717 TryCatch try_catch;
11719 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
11720 CHECK(try_catch.HasCaught());
11722 CHECK(result.IsEmpty());
11724 result = another->GetRealNamedProperty(v8_str("f"));
11725 CHECK(try_catch.HasCaught());
11727 CHECK(result.IsEmpty());
11729 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
11730 CHECK(try_catch.HasCaught());
11732 CHECK(result.IsEmpty());
11734 result = another->Get(v8_str("f"));
11735 CHECK(try_catch.HasCaught());
11737 CHECK(result.IsEmpty());
11739 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
11740 CHECK(try_catch.HasCaught());
11742 CHECK(result.IsEmpty());
11744 result = with_js_getter->Get(v8_str("f"));
11745 CHECK(try_catch.HasCaught());
11747 CHECK(result.IsEmpty());
11751 static void ThrowingCallbackWithTryCatch(
11752 const v8::FunctionCallbackInfo<v8::Value>& args) {
11753 TryCatch try_catch;
11754 // Verboseness is important: it triggers message delivery which can call into
11756 try_catch.SetVerbose(true);
11757 CompileRun("throw 'from JS';");
11758 CHECK(try_catch.HasCaught());
11759 CHECK(!i::Isolate::Current()->has_pending_exception());
11760 CHECK(!i::Isolate::Current()->has_scheduled_exception());
11764 static int call_depth;
11767 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
11768 TryCatch try_catch;
11772 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
11773 if (--call_depth) CompileRun("throw 'ThrowInJS';");
11777 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
11778 if (--call_depth) ThrowException(v8_str("ThrowViaApi"));
11782 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
11783 Handle<String> errorMessageString = message->Get();
11784 CHECK(!errorMessageString.IsEmpty());
11785 message->GetStackTrace();
11786 message->GetScriptResourceName();
11790 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
11791 LocalContext context;
11792 HandleScope scope(context->GetIsolate());
11794 Local<Function> func =
11795 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction();
11796 context->Global()->Set(v8_str("func"), func);
11798 MessageCallback callbacks[] =
11799 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
11800 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
11801 MessageCallback callback = callbacks[i];
11802 if (callback != NULL) {
11803 V8::AddMessageListener(callback);
11805 // Some small number to control number of times message handler should
11806 // throw an exception.
11809 "var thrown = false;\n"
11810 "try { func(); } catch(e) { thrown = true; }\n"
11812 if (callback != NULL) {
11813 V8::RemoveMessageListeners(callback);
11819 static void ParentGetter(Local<String> name,
11820 const v8::PropertyCallbackInfo<v8::Value>& info) {
11821 ApiTestFuzzer::Fuzz();
11822 info.GetReturnValue().Set(v8_num(1));
11826 static void ChildGetter(Local<String> name,
11827 const v8::PropertyCallbackInfo<v8::Value>& info) {
11828 ApiTestFuzzer::Fuzz();
11829 info.GetReturnValue().Set(v8_num(42));
11833 THREADED_TEST(Overriding) {
11834 i::FLAG_es5_readonly = true;
11835 LocalContext context;
11836 v8::HandleScope scope(context->GetIsolate());
11838 // Parent template.
11839 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New();
11840 Local<ObjectTemplate> parent_instance_templ =
11841 parent_templ->InstanceTemplate();
11842 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
11844 // Template that inherits from the parent template.
11845 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New();
11846 Local<ObjectTemplate> child_instance_templ =
11847 child_templ->InstanceTemplate();
11848 child_templ->Inherit(parent_templ);
11849 // Override 'f'. The child version of 'f' should get called for child
11851 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
11852 // Add 'g' twice. The 'g' added last should get called for instances.
11853 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
11854 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
11856 // Add 'h' as an accessor to the proto template with ReadOnly attributes
11857 // so 'h' can be shadowed on the instance object.
11858 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
11859 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
11860 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11862 // Add 'i' as an accessor to the instance template with ReadOnly attributes
11863 // but the attribute does not have effect because it is duplicated with
11865 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
11866 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11870 // Instantiate the child template.
11871 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
11873 // Check that the child function overrides the parent one.
11874 context->Global()->Set(v8_str("o"), instance);
11875 Local<Value> value = v8_compile("o.f")->Run();
11876 // Check that the 'g' that was added last is hit.
11877 CHECK_EQ(42, value->Int32Value());
11878 value = v8_compile("o.g")->Run();
11879 CHECK_EQ(42, value->Int32Value());
11881 // Check that 'h' cannot be shadowed.
11882 value = v8_compile("o.h = 3; o.h")->Run();
11883 CHECK_EQ(1, value->Int32Value());
11885 // Check that 'i' cannot be shadowed or changed.
11886 value = v8_compile("o.i = 3; o.i")->Run();
11887 CHECK_EQ(42, value->Int32Value());
11891 static void IsConstructHandler(
11892 const v8::FunctionCallbackInfo<v8::Value>& args) {
11893 ApiTestFuzzer::Fuzz();
11894 args.GetReturnValue().Set(args.IsConstructCall());
11898 THREADED_TEST(IsConstructCall) {
11899 v8::HandleScope scope(v8::Isolate::GetCurrent());
11901 // Function template with call handler.
11902 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
11903 templ->SetCallHandler(IsConstructHandler);
11905 LocalContext context;
11907 context->Global()->Set(v8_str("f"), templ->GetFunction());
11908 Local<Value> value = v8_compile("f()")->Run();
11909 CHECK(!value->BooleanValue());
11910 value = v8_compile("new f()")->Run();
11911 CHECK(value->BooleanValue());
11915 THREADED_TEST(ObjectProtoToString) {
11916 v8::HandleScope scope(v8::Isolate::GetCurrent());
11917 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
11918 templ->SetClassName(v8_str("MyClass"));
11920 LocalContext context;
11922 Local<String> customized_tostring = v8_str("customized toString");
11924 // Replace Object.prototype.toString
11925 v8_compile("Object.prototype.toString = function() {"
11926 " return 'customized toString';"
11929 // Normal ToString call should call replaced Object.prototype.toString
11930 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11931 Local<String> value = instance->ToString();
11932 CHECK(value->IsString() && value->Equals(customized_tostring));
11934 // ObjectProtoToString should not call replace toString function.
11935 value = instance->ObjectProtoToString();
11936 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11939 value = context->Global()->ObjectProtoToString();
11940 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11942 // Check ordinary object
11943 Local<Value> object = v8_compile("new Object()")->Run();
11944 value = object.As<v8::Object>()->ObjectProtoToString();
11945 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11949 THREADED_TEST(ObjectGetConstructorName) {
11950 LocalContext context;
11951 v8::HandleScope scope(context->GetIsolate());
11952 v8_compile("function Parent() {};"
11953 "function Child() {};"
11954 "Child.prototype = new Parent();"
11955 "var outer = { inner: function() { } };"
11956 "var p = new Parent();"
11957 "var c = new Child();"
11958 "var x = new outer.inner();")->Run();
11960 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
11961 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
11962 v8_str("Parent")));
11964 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
11965 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
11968 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
11969 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
11970 v8_str("outer.inner")));
11974 bool ApiTestFuzzer::fuzzing_ = false;
11975 i::Semaphore* ApiTestFuzzer::all_tests_done_=
11976 i::OS::CreateSemaphore(0);
11977 int ApiTestFuzzer::active_tests_;
11978 int ApiTestFuzzer::tests_being_run_;
11979 int ApiTestFuzzer::current_;
11982 // We are in a callback and want to switch to another thread (if we
11983 // are currently running the thread fuzzing test).
11984 void ApiTestFuzzer::Fuzz() {
11985 if (!fuzzing_) return;
11986 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
11987 test->ContextSwitch();
11991 // Let the next thread go. Since it is also waiting on the V8 lock it may
11992 // not start immediately.
11993 bool ApiTestFuzzer::NextThread() {
11994 int test_position = GetNextTestNumber();
11995 const char* test_name = RegisterThreadedTest::nth(current_)->name();
11996 if (test_position == current_) {
11998 printf("Stay with %s\n", test_name);
12001 if (kLogThreading) {
12002 printf("Switch from %s to %s\n",
12004 RegisterThreadedTest::nth(test_position)->name());
12006 current_ = test_position;
12007 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal();
12012 void ApiTestFuzzer::Run() {
12013 // When it is our turn...
12016 // ... get the V8 lock and start running the test.
12017 v8::Locker locker(CcTest::default_isolate());
12020 // This test finished.
12023 // If it was the last then signal that fact.
12024 if (active_tests_ == 0) {
12025 all_tests_done_->Signal();
12027 // Otherwise select a new test and start that.
12033 static unsigned linear_congruential_generator;
12036 void ApiTestFuzzer::SetUp(PartOfTest part) {
12037 linear_congruential_generator = i::FLAG_testing_prng_seed;
12039 int count = RegisterThreadedTest::count();
12040 int start = count * part / (LAST_PART + 1);
12041 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
12042 active_tests_ = tests_being_run_ = end - start + 1;
12043 for (int i = 0; i < tests_being_run_; i++) {
12044 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
12046 for (int i = 0; i < active_tests_; i++) {
12047 RegisterThreadedTest::nth(i)->fuzzer_->Start();
12052 static void CallTestNumber(int test_number) {
12053 (RegisterThreadedTest::nth(test_number)->callback())();
12057 void ApiTestFuzzer::RunAllTests() {
12058 // Set off the first test.
12061 // Wait till they are all done.
12062 all_tests_done_->Wait();
12066 int ApiTestFuzzer::GetNextTestNumber() {
12069 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
12070 linear_congruential_generator *= 1664525u;
12071 linear_congruential_generator += 1013904223u;
12072 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
12077 void ApiTestFuzzer::ContextSwitch() {
12078 // If the new thread is the same as the current thread there is nothing to do.
12079 if (NextThread()) {
12080 // Now it can start.
12081 v8::Unlocker unlocker(CcTest::default_isolate());
12082 // Wait till someone starts us again.
12089 void ApiTestFuzzer::TearDown() {
12091 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
12092 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
12093 if (fuzzer != NULL) fuzzer->Join();
12098 // Lets not be needlessly self-referential.
12100 // TODO(mstarzinger): Disabled in GC stress mode for now, we should find the
12101 // correct timeout for this an re-enable this test again
12102 if (i::FLAG_stress_compaction) return;
12103 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
12104 ApiTestFuzzer::RunAllTests();
12105 ApiTestFuzzer::TearDown();
12110 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
12111 ApiTestFuzzer::RunAllTests();
12112 ApiTestFuzzer::TearDown();
12117 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
12118 ApiTestFuzzer::RunAllTests();
12119 ApiTestFuzzer::TearDown();
12124 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
12125 ApiTestFuzzer::RunAllTests();
12126 ApiTestFuzzer::TearDown();
12130 void ApiTestFuzzer::CallTest() {
12132 printf("Start test %d\n", test_number_);
12133 CallTestNumber(test_number_);
12135 printf("End test %d\n", test_number_);
12139 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
12140 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12141 ApiTestFuzzer::Fuzz();
12142 v8::Unlocker unlocker(CcTest::default_isolate());
12143 const char* code = "throw 7;";
12145 v8::Locker nested_locker(CcTest::default_isolate());
12146 v8::HandleScope scope(args.GetIsolate());
12147 v8::Handle<Value> exception;
12148 { v8::TryCatch try_catch;
12149 v8::Handle<Value> value = CompileRun(code);
12150 CHECK(value.IsEmpty());
12151 CHECK(try_catch.HasCaught());
12152 // Make sure to wrap the exception in a new handle because
12153 // the handle returned from the TryCatch is destroyed
12154 // when the TryCatch is destroyed.
12155 exception = Local<Value>::New(try_catch.Exception());
12157 v8::ThrowException(exception);
12162 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
12163 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12164 ApiTestFuzzer::Fuzz();
12165 v8::Unlocker unlocker(CcTest::default_isolate());
12166 const char* code = "throw 7;";
12168 v8::Locker nested_locker(CcTest::default_isolate());
12169 v8::HandleScope scope(args.GetIsolate());
12170 v8::Handle<Value> value = CompileRun(code);
12171 CHECK(value.IsEmpty());
12172 args.GetReturnValue().Set(v8_str("foo"));
12177 // These are locking tests that don't need to be run again
12178 // as part of the locking aggregation tests.
12179 TEST(NestedLockers) {
12180 v8::Locker locker(CcTest::default_isolate());
12181 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12183 v8::HandleScope scope(env->GetIsolate());
12184 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS);
12185 Local<Function> fun = fun_templ->GetFunction();
12186 env->Global()->Set(v8_str("throw_in_js"), fun);
12187 Local<Script> script = v8_compile("(function () {"
12195 CHECK_EQ(91, script->Run()->Int32Value());
12199 // These are locking tests that don't need to be run again
12200 // as part of the locking aggregation tests.
12201 TEST(NestedLockersNoTryCatch) {
12202 v8::Locker locker(CcTest::default_isolate());
12204 v8::HandleScope scope(env->GetIsolate());
12205 Local<v8::FunctionTemplate> fun_templ =
12206 v8::FunctionTemplate::New(ThrowInJSNoCatch);
12207 Local<Function> fun = fun_templ->GetFunction();
12208 env->Global()->Set(v8_str("throw_in_js"), fun);
12209 Local<Script> script = v8_compile("(function () {"
12217 CHECK_EQ(91, script->Run()->Int32Value());
12221 THREADED_TEST(RecursiveLocking) {
12222 v8::Locker locker(CcTest::default_isolate());
12224 v8::Locker locker2(CcTest::default_isolate());
12225 CHECK(v8::Locker::IsLocked(CcTest::default_isolate()));
12230 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
12231 ApiTestFuzzer::Fuzz();
12232 v8::Unlocker unlocker(CcTest::default_isolate());
12236 THREADED_TEST(LockUnlockLock) {
12238 v8::Locker locker(CcTest::default_isolate());
12239 v8::HandleScope scope(CcTest::default_isolate());
12241 Local<v8::FunctionTemplate> fun_templ =
12242 v8::FunctionTemplate::New(UnlockForAMoment);
12243 Local<Function> fun = fun_templ->GetFunction();
12244 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
12245 Local<Script> script = v8_compile("(function () {"
12246 " unlock_for_a_moment();"
12249 CHECK_EQ(42, script->Run()->Int32Value());
12252 v8::Locker locker(CcTest::default_isolate());
12253 v8::HandleScope scope(CcTest::default_isolate());
12255 Local<v8::FunctionTemplate> fun_templ =
12256 v8::FunctionTemplate::New(UnlockForAMoment);
12257 Local<Function> fun = fun_templ->GetFunction();
12258 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
12259 Local<Script> script = v8_compile("(function () {"
12260 " unlock_for_a_moment();"
12263 CHECK_EQ(42, script->Run()->Int32Value());
12268 static int GetGlobalObjectsCount() {
12269 i::Isolate::Current()->heap()->EnsureHeapIsIterable();
12271 i::HeapIterator it(HEAP);
12272 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
12273 if (object->IsJSGlobalObject()) count++;
12278 static void CheckSurvivingGlobalObjectsCount(int expected) {
12279 // We need to collect all garbage twice to be sure that everything
12280 // has been collected. This is because inline caches are cleared in
12281 // the first garbage collection but some of the maps have already
12282 // been marked at that point. Therefore some of the maps are not
12283 // collected until the second garbage collection.
12284 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12285 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
12286 int count = GetGlobalObjectsCount();
12288 if (count != expected) HEAP->TracePathToGlobal();
12290 CHECK_EQ(expected, count);
12294 TEST(DontLeakGlobalObjects) {
12295 // Regression test for issues 1139850 and 1174891.
12297 v8::V8::Initialize();
12299 for (int i = 0; i < 5; i++) {
12300 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12301 LocalContext context;
12303 v8::V8::ContextDisposedNotification();
12304 CheckSurvivingGlobalObjectsCount(0);
12306 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12307 LocalContext context;
12308 v8_compile("Date")->Run();
12310 v8::V8::ContextDisposedNotification();
12311 CheckSurvivingGlobalObjectsCount(0);
12313 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12314 LocalContext context;
12315 v8_compile("/aaa/")->Run();
12317 v8::V8::ContextDisposedNotification();
12318 CheckSurvivingGlobalObjectsCount(0);
12320 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12321 const char* extension_list[] = { "v8/gc" };
12322 v8::ExtensionConfiguration extensions(1, extension_list);
12323 LocalContext context(&extensions);
12324 v8_compile("gc();")->Run();
12326 v8::V8::ContextDisposedNotification();
12327 CheckSurvivingGlobalObjectsCount(0);
12332 v8::Persistent<v8::Object> some_object;
12333 v8::Persistent<v8::Object> bad_handle;
12335 void NewPersistentHandleCallback(v8::Isolate* isolate,
12336 v8::Persistent<v8::Value>* handle,
12338 v8::HandleScope scope(isolate);
12339 bad_handle.Reset(isolate, some_object);
12340 handle->Dispose(isolate);
12344 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
12345 LocalContext context;
12346 v8::Isolate* isolate = context->GetIsolate();
12348 v8::Persistent<v8::Object> handle1, handle2;
12350 v8::HandleScope scope(isolate);
12351 some_object.Reset(isolate, v8::Object::New());
12352 handle1.Reset(isolate, v8::Object::New());
12353 handle2.Reset(isolate, v8::Object::New());
12355 // Note: order is implementation dependent alas: currently
12356 // global handle nodes are processed by PostGarbageCollectionProcessing
12357 // in reverse allocation order, so if second allocated handle is deleted,
12358 // weak callback of the first handle would be able to 'reallocate' it.
12359 handle1.MakeWeak<v8::Value, void>(NULL, NewPersistentHandleCallback);
12360 handle2.Dispose(isolate);
12361 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12365 v8::Persistent<v8::Object> to_be_disposed;
12367 void DisposeAndForceGcCallback(v8::Isolate* isolate,
12368 v8::Persistent<v8::Value>* handle,
12370 to_be_disposed.Dispose(isolate);
12371 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12372 handle->Dispose(isolate);
12376 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
12377 LocalContext context;
12378 v8::Isolate* isolate = context->GetIsolate();
12380 v8::Persistent<v8::Object> handle1, handle2;
12382 v8::HandleScope scope(isolate);
12383 handle1.Reset(isolate, v8::Object::New());
12384 handle2.Reset(isolate, v8::Object::New());
12386 handle1.MakeWeak<v8::Value, void>(NULL, DisposeAndForceGcCallback);
12387 to_be_disposed.Reset(isolate, handle2);
12388 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12391 void DisposingCallback(v8::Isolate* isolate,
12392 v8::Persistent<v8::Value>* handle,
12394 handle->Dispose(isolate);
12397 void HandleCreatingCallback(v8::Isolate* isolate,
12398 v8::Persistent<v8::Value>* handle,
12400 v8::HandleScope scope(isolate);
12401 v8::Persistent<v8::Object>(isolate, v8::Object::New());
12402 handle->Dispose(isolate);
12406 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
12407 LocalContext context;
12408 v8::Isolate* isolate = context->GetIsolate();
12410 v8::Persistent<v8::Object> handle1, handle2, handle3;
12412 v8::HandleScope scope(isolate);
12413 handle3.Reset(isolate, v8::Object::New());
12414 handle2.Reset(isolate, v8::Object::New());
12415 handle1.Reset(isolate, v8::Object::New());
12417 handle2.MakeWeak<v8::Value, void>(NULL, DisposingCallback);
12418 handle3.MakeWeak<v8::Value, void>(NULL, HandleCreatingCallback);
12419 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
12423 THREADED_TEST(CheckForCrossContextObjectLiterals) {
12424 v8::V8::Initialize();
12427 const char* sources[nof] = {
12428 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
12432 for (int i = 0; i < nof; i++) {
12433 const char* source = sources[i];
12434 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12435 LocalContext context;
12436 CompileRun(source);
12438 { v8::HandleScope scope(v8::Isolate::GetCurrent());
12439 LocalContext context;
12440 CompileRun(source);
12446 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
12447 v8::HandleScope inner(env->GetIsolate());
12449 v8::Handle<Value> three = v8_num(3);
12450 v8::Handle<Value> value = inner.Close(three);
12456 THREADED_TEST(NestedHandleScopeAndContexts) {
12457 v8::Isolate* isolate = v8::Isolate::GetCurrent();
12458 v8::HandleScope outer(isolate);
12459 v8::Local<Context> env = Context::New(isolate);
12461 v8::Handle<Value> value = NestedScope(env);
12462 v8::Handle<String> str(value->ToString());
12463 CHECK(!str.IsEmpty());
12468 static bool MatchPointers(void* key1, void* key2) {
12469 return key1 == key2;
12473 struct SymbolInfo {
12480 class SetFunctionEntryHookTest {
12482 SetFunctionEntryHookTest() {
12483 CHECK(instance_ == NULL);
12486 ~SetFunctionEntryHookTest() {
12487 CHECK(instance_ == this);
12492 symbol_locations_.clear();
12493 invocations_.clear();
12496 void OnJitEvent(const v8::JitCodeEvent* event);
12497 static void JitEvent(const v8::JitCodeEvent* event) {
12498 CHECK(instance_ != NULL);
12499 instance_->OnJitEvent(event);
12502 void OnEntryHook(uintptr_t function,
12503 uintptr_t return_addr_location);
12504 static void EntryHook(uintptr_t function,
12505 uintptr_t return_addr_location) {
12506 CHECK(instance_ != NULL);
12507 instance_->OnEntryHook(function, return_addr_location);
12510 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12511 CHECK(instance_ != NULL);
12512 args.GetReturnValue().Set(v8_num(42));
12514 void RunLoopInNewEnv(v8::Isolate* isolate);
12516 // Records addr as location of symbol.
12517 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
12519 // Finds the symbol containing addr
12520 SymbolInfo* FindSymbolForAddr(i::Address addr);
12521 // Returns the number of invocations where the caller name contains
12522 // \p caller_name and the function name contains \p function_name.
12523 int CountInvocations(const char* caller_name,
12524 const char* function_name);
12526 i::Handle<i::JSFunction> foo_func_;
12527 i::Handle<i::JSFunction> bar_func_;
12529 typedef std::map<size_t, SymbolInfo> SymbolMap;
12530 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
12531 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
12532 SymbolMap symbols_;
12533 SymbolLocationMap symbol_locations_;
12534 InvocationMap invocations_;
12536 static SetFunctionEntryHookTest* instance_;
12538 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
12541 // Returns true if addr is in the range [start, start+len).
12542 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
12543 if (start <= addr && start + len > addr)
12549 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
12550 SymbolInfo* symbol) {
12551 // Insert the symbol at the new location.
12552 SymbolLocationMap::iterator it =
12553 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
12554 // Now erase symbols to the left and right that overlap this one.
12555 while (it != symbol_locations_.begin()) {
12556 SymbolLocationMap::iterator left = it;
12558 if (!Overlaps(left->first, left->second->size, addr))
12560 symbol_locations_.erase(left);
12563 // Now erase symbols to the left and right that overlap this one.
12565 SymbolLocationMap::iterator right = it;
12567 if (right == symbol_locations_.end())
12569 if (!Overlaps(addr, symbol->size, right->first))
12571 symbol_locations_.erase(right);
12576 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
12577 switch (event->type) {
12578 case v8::JitCodeEvent::CODE_ADDED: {
12579 CHECK(event->code_start != NULL);
12580 CHECK_NE(0, static_cast<int>(event->code_len));
12581 CHECK(event->name.str != NULL);
12582 size_t symbol_id = symbols_.size();
12584 // Record the new symbol.
12585 SymbolInfo& info = symbols_[symbol_id];
12586 info.id = symbol_id;
12587 info.size = event->code_len;
12588 info.name.assign(event->name.str, event->name.str + event->name.len);
12590 // And record it's location.
12591 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
12595 case v8::JitCodeEvent::CODE_MOVED: {
12596 // We would like to never see code move that we haven't seen before,
12597 // but the code creation event does not happen until the line endings
12598 // have been calculated (this is so that we can report the line in the
12599 // script at which the function source is found, see
12600 // Compiler::RecordFunctionCompilation) and the line endings
12601 // calculations can cause a GC, which can move the newly created code
12602 // before its existence can be logged.
12603 SymbolLocationMap::iterator it(
12604 symbol_locations_.find(
12605 reinterpret_cast<i::Address>(event->code_start)));
12606 if (it != symbol_locations_.end()) {
12607 // Found a symbol at this location, move it.
12608 SymbolInfo* info = it->second;
12609 symbol_locations_.erase(it);
12610 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
12619 void SetFunctionEntryHookTest::OnEntryHook(
12620 uintptr_t function, uintptr_t return_addr_location) {
12621 // Get the function's code object.
12622 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
12623 reinterpret_cast<i::Address>(function));
12624 CHECK(function_code != NULL);
12626 // Then try and look up the caller's code object.
12627 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
12629 // Count the invocation.
12630 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
12631 SymbolInfo* function_symbol =
12632 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
12633 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
12635 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
12636 // Check that we have a symbol for the "bar" function at the right location.
12637 SymbolLocationMap::iterator it(
12638 symbol_locations_.find(function_code->instruction_start()));
12639 CHECK(it != symbol_locations_.end());
12642 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
12643 // Check that we have a symbol for "foo" at the right location.
12644 SymbolLocationMap::iterator it(
12645 symbol_locations_.find(function_code->instruction_start()));
12646 CHECK(it != symbol_locations_.end());
12651 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
12652 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
12653 // Do we have a direct hit on a symbol?
12654 if (it != symbol_locations_.end()) {
12655 if (it->first == addr)
12659 // If not a direct hit, it'll have to be the previous symbol.
12660 if (it == symbol_locations_.begin())
12664 size_t offs = addr - it->first;
12665 if (offs < it->second->size)
12672 int SetFunctionEntryHookTest::CountInvocations(
12673 const char* caller_name, const char* function_name) {
12674 InvocationMap::iterator it(invocations_.begin());
12675 int invocations = 0;
12676 for (; it != invocations_.end(); ++it) {
12677 SymbolInfo* caller = it->first.first;
12678 SymbolInfo* function = it->first.second;
12680 // Filter out non-matching functions.
12681 if (function_name != NULL) {
12682 if (function->name.find(function_name) == std::string::npos)
12686 // Filter out non-matching callers.
12687 if (caller_name != NULL) {
12688 if (caller == NULL)
12690 if (caller->name.find(caller_name) == std::string::npos)
12694 // It matches add the invocation count to the tally.
12695 invocations += it->second;
12698 return invocations;
12702 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
12703 v8::HandleScope outer(isolate);
12704 v8::Local<Context> env = Context::New(isolate);
12707 Local<ObjectTemplate> t = ObjectTemplate::New();
12708 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(RuntimeCallback));
12709 env->Global()->Set(v8_str("obj"), t->NewInstance());
12711 const char* script =
12712 "function bar() {\n"
12714 " for (i = 0; i < 100; ++i)\n"
12718 "function foo(i) { return i * i; }\n"
12719 "// Invoke on the runtime function.\n"
12721 CompileRun(script);
12722 bar_func_ = i::Handle<i::JSFunction>::cast(
12723 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
12724 ASSERT(!bar_func_.is_null());
12727 i::Handle<i::JSFunction>::cast(
12728 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
12729 ASSERT(!foo_func_.is_null());
12731 v8::Handle<v8::Value> value = CompileRun("bar();");
12732 CHECK(value->IsNumber());
12733 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12735 // Test the optimized codegen path.
12736 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
12738 CHECK(value->IsNumber());
12739 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12745 void SetFunctionEntryHookTest::RunTest() {
12746 // Work in a new isolate throughout.
12747 v8::Isolate* isolate = v8::Isolate::New();
12749 // Test setting the entry hook on the new isolate.
12750 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook));
12752 // Replacing the hook, once set should fail.
12753 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
12756 v8::Isolate::Scope scope(isolate);
12758 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent);
12760 RunLoopInNewEnv(isolate);
12762 // Check the exepected invocation counts.
12763 CHECK_EQ(2, CountInvocations(NULL, "bar"));
12764 CHECK_EQ(200, CountInvocations("bar", "foo"));
12765 CHECK_EQ(200, CountInvocations(NULL, "foo"));
12767 // Verify that we have an entry hook on some specific stubs.
12768 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
12769 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
12770 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
12772 isolate->Dispose();
12776 // Make sure a second isolate is unaffected by the previous entry hook.
12777 isolate = v8::Isolate::New();
12779 v8::Isolate::Scope scope(isolate);
12781 // Reset the entry count to zero and set the entry hook.
12782 RunLoopInNewEnv(isolate);
12784 // We should record no invocations in this isolate.
12785 CHECK_EQ(0, static_cast<int>(invocations_.size()));
12787 // Since the isolate has been used, we shouldn't be able to set an entry
12789 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook));
12791 isolate->Dispose();
12795 TEST(SetFunctionEntryHook) {
12796 // FunctionEntryHook does not work well with experimental natives.
12797 // Experimental natives are compiled during snapshot deserialization.
12798 // This test breaks because InstallGetter (function from snapshot that
12799 // only gets called from experimental natives) is compiled with entry hooks.
12800 i::FLAG_harmony_typed_arrays = false;
12801 i::FLAG_harmony_array_buffer = false;
12803 i::FLAG_allow_natives_syntax = true;
12804 i::FLAG_use_inlining = false;
12806 SetFunctionEntryHookTest test;
12811 static i::HashMap* code_map = NULL;
12812 static i::HashMap* jitcode_line_info = NULL;
12813 static int saw_bar = 0;
12814 static int move_events = 0;
12817 static bool FunctionNameIs(const char* expected,
12818 const v8::JitCodeEvent* event) {
12819 // Log lines for functions are of the general form:
12820 // "LazyCompile:<type><function_name>", where the type is one of
12822 static const char kPreamble[] = "LazyCompile:";
12823 static size_t kPreambleLen = sizeof(kPreamble) - 1;
12825 if (event->name.len < sizeof(kPreamble) - 1 ||
12826 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
12830 const char* tail = event->name.str + kPreambleLen;
12831 size_t tail_len = event->name.len - kPreambleLen;
12832 size_t expected_len = strlen(expected);
12833 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
12838 // Check for tails like 'bar :1'.
12839 if (tail_len > expected_len + 2 &&
12840 tail[expected_len] == ' ' &&
12841 tail[expected_len + 1] == ':' &&
12842 tail[expected_len + 2] &&
12843 !strncmp(tail, expected, expected_len)) {
12847 if (tail_len != expected_len)
12850 return strncmp(tail, expected, expected_len) == 0;
12854 static void event_handler(const v8::JitCodeEvent* event) {
12855 CHECK(event != NULL);
12856 CHECK(code_map != NULL);
12857 CHECK(jitcode_line_info != NULL);
12859 class DummyJitCodeLineInfo {
12862 switch (event->type) {
12863 case v8::JitCodeEvent::CODE_ADDED: {
12864 CHECK(event->code_start != NULL);
12865 CHECK_NE(0, static_cast<int>(event->code_len));
12866 CHECK(event->name.str != NULL);
12867 i::HashMap::Entry* entry =
12868 code_map->Lookup(event->code_start,
12869 i::ComputePointerHash(event->code_start),
12871 entry->value = reinterpret_cast<void*>(event->code_len);
12873 if (FunctionNameIs("bar", event)) {
12879 case v8::JitCodeEvent::CODE_MOVED: {
12880 uint32_t hash = i::ComputePointerHash(event->code_start);
12881 // We would like to never see code move that we haven't seen before,
12882 // but the code creation event does not happen until the line endings
12883 // have been calculated (this is so that we can report the line in the
12884 // script at which the function source is found, see
12885 // Compiler::RecordFunctionCompilation) and the line endings
12886 // calculations can cause a GC, which can move the newly created code
12887 // before its existence can be logged.
12888 i::HashMap::Entry* entry =
12889 code_map->Lookup(event->code_start, hash, false);
12890 if (entry != NULL) {
12893 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
12894 code_map->Remove(event->code_start, hash);
12896 entry = code_map->Lookup(event->new_code_start,
12897 i::ComputePointerHash(event->new_code_start),
12899 CHECK(entry != NULL);
12900 entry->value = reinterpret_cast<void*>(event->code_len);
12905 case v8::JitCodeEvent::CODE_REMOVED:
12906 // Object/code removal events are currently not dispatched from the GC.
12910 // For CODE_START_LINE_INFO_RECORDING event, we will create one
12911 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
12912 // record it in jitcode_line_info.
12913 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
12914 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
12915 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
12916 temp_event->user_data = line_info;
12917 i::HashMap::Entry* entry =
12918 jitcode_line_info->Lookup(line_info,
12919 i::ComputePointerHash(line_info),
12921 entry->value = reinterpret_cast<void*>(line_info);
12924 // For these two events, we will check whether the event->user_data
12925 // data structure is created before during CODE_START_LINE_INFO_RECORDING
12926 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
12927 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
12928 CHECK(event->user_data != NULL);
12929 uint32_t hash = i::ComputePointerHash(event->user_data);
12930 i::HashMap::Entry* entry =
12931 jitcode_line_info->Lookup(event->user_data, hash, false);
12932 CHECK(entry != NULL);
12933 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
12937 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
12938 CHECK(event->user_data != NULL);
12939 uint32_t hash = i::ComputePointerHash(event->user_data);
12940 i::HashMap::Entry* entry =
12941 jitcode_line_info->Lookup(event->user_data, hash, false);
12942 CHECK(entry != NULL);
12947 // Impossible event.
12954 TEST(SetJitCodeEventHandler) {
12955 i::FLAG_stress_compaction = true;
12956 i::FLAG_incremental_marking = false;
12957 const char* script =
12960 " for (i = 0; i < 100; ++i)"
12964 "function foo(i) { return i * i; };"
12967 // Run this test in a new isolate to make sure we don't
12968 // have remnants of state from other code.
12969 v8::Isolate* isolate = v8::Isolate::New();
12973 v8::HandleScope scope(isolate);
12974 i::HashMap code(MatchPointers);
12977 i::HashMap lineinfo(MatchPointers);
12978 jitcode_line_info = &lineinfo;
12983 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
12985 // Generate new code objects sparsely distributed across several
12986 // different fragmented code-space pages.
12987 const int kIterations = 10;
12988 for (int i = 0; i < kIterations; ++i) {
12990 i::AlwaysAllocateScope always_allocate;
12991 SimulateFullSpace(HEAP->code_space());
12992 CompileRun(script);
12994 // Keep a strong reference to the code object in the handle scope.
12995 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
12996 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
12997 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
12998 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
13000 // Clear the compilation cache to get more wastage.
13001 ISOLATE->compilation_cache()->Clear();
13004 // Force code movement.
13005 HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
13007 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
13009 CHECK_LE(kIterations, saw_bar);
13010 CHECK_LT(0, move_events);
13013 jitcode_line_info = NULL;
13017 isolate->Dispose();
13019 // Do this in a new isolate.
13020 isolate = v8::Isolate::New();
13023 // Verify that we get callbacks for existing code objects when we
13024 // request enumeration of existing code.
13026 v8::HandleScope scope(isolate);
13028 CompileRun(script);
13030 // Now get code through initial iteration.
13031 i::HashMap code(MatchPointers);
13034 i::HashMap lineinfo(MatchPointers);
13035 jitcode_line_info = &lineinfo;
13037 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler);
13038 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
13040 jitcode_line_info = NULL;
13041 // We expect that we got some events. Note that if we could get code removal
13042 // notifications, we could compare two collections, one created by listening
13043 // from the time of creation of an isolate, and the other by subscribing
13044 // with EnumExisting.
13045 CHECK_LT(0, code.occupancy());
13051 isolate->Dispose();
13055 static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
13058 THREADED_TEST(ExternalAllocatedMemory) {
13059 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13060 v8::HandleScope outer(isolate);
13061 v8::Local<Context> env(Context::New(isolate));
13062 CHECK(!env.IsEmpty());
13063 const intptr_t kSize = 1024*1024;
13064 int64_t baseline = cast(isolate->AdjustAmountOfExternalAllocatedMemory(0));
13065 CHECK_EQ(baseline + cast(kSize),
13066 cast(isolate->AdjustAmountOfExternalAllocatedMemory(kSize)));
13068 cast(isolate->AdjustAmountOfExternalAllocatedMemory(-kSize)));
13072 THREADED_TEST(DisposeEnteredContext) {
13073 LocalContext outer;
13074 v8::Isolate* isolate = outer->GetIsolate();
13075 v8::Persistent<v8::Context> inner;
13077 v8::HandleScope scope(isolate);
13078 inner.Reset(isolate, v8::Context::New(isolate));
13080 v8::HandleScope scope(isolate);
13082 // Don't want a handle here, so do this unsafely
13083 v8::Handle<v8::Context> inner_local =
13084 v8::Utils::Convert<i::Object, v8::Context>(
13085 v8::Utils::OpenPersistent(inner));
13086 inner_local->Enter();
13089 inner_local->Exit();
13094 // Regression test for issue 54, object templates with internal fields
13095 // but no accessors or interceptors did not get their internal field
13096 // count set on instances.
13097 THREADED_TEST(Regress54) {
13098 LocalContext context;
13099 v8::Isolate* isolate = context->GetIsolate();
13100 v8::HandleScope outer(isolate);
13101 static v8::Persistent<v8::ObjectTemplate> templ;
13102 if (templ.IsEmpty()) {
13103 v8::HandleScope inner(isolate);
13104 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New();
13105 local->SetInternalFieldCount(1);
13106 templ.Reset(isolate, inner.Close(local));
13108 v8::Handle<v8::Object> result =
13109 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
13110 CHECK_EQ(1, result->InternalFieldCount());
13114 // If part of the threaded tests, this test makes ThreadingTest fail
13116 TEST(CatchStackOverflow) {
13117 LocalContext context;
13118 v8::HandleScope scope(context->GetIsolate());
13119 v8::TryCatch try_catch;
13120 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(
13126 v8::Handle<v8::Value> result = script->Run();
13127 CHECK(result.IsEmpty());
13131 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
13132 const char* resource_name,
13134 v8::HandleScope scope(v8::Isolate::GetCurrent());
13135 v8::TryCatch try_catch;
13136 v8::Handle<v8::Value> result = script->Run();
13137 CHECK(result.IsEmpty());
13138 CHECK(try_catch.HasCaught());
13139 v8::Handle<v8::Message> message = try_catch.Message();
13140 CHECK(!message.IsEmpty());
13141 CHECK_EQ(10 + line_offset, message->GetLineNumber());
13142 CHECK_EQ(91, message->GetStartPosition());
13143 CHECK_EQ(92, message->GetEndPosition());
13144 CHECK_EQ(2, message->GetStartColumn());
13145 CHECK_EQ(3, message->GetEndColumn());
13146 v8::String::Utf8Value line(message->GetSourceLine());
13147 CHECK_EQ(" throw 'nirk';", *line);
13148 v8::String::Utf8Value name(message->GetScriptResourceName());
13149 CHECK_EQ(resource_name, *name);
13153 THREADED_TEST(TryCatchSourceInfo) {
13154 LocalContext context;
13155 v8::HandleScope scope(context->GetIsolate());
13156 v8::Handle<v8::String> source = v8::String::New(
13157 "function Foo() {\n"
13161 "function Bar() {\n"
13165 "function Baz() {\n"
13171 const char* resource_name;
13172 v8::Handle<v8::Script> script;
13173 resource_name = "test.js";
13174 script = v8::Script::Compile(source, v8::String::New(resource_name));
13175 CheckTryCatchSourceInfo(script, resource_name, 0);
13177 resource_name = "test1.js";
13178 v8::ScriptOrigin origin1(v8::String::New(resource_name));
13179 script = v8::Script::Compile(source, &origin1);
13180 CheckTryCatchSourceInfo(script, resource_name, 0);
13182 resource_name = "test2.js";
13183 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7));
13184 script = v8::Script::Compile(source, &origin2);
13185 CheckTryCatchSourceInfo(script, resource_name, 7);
13189 THREADED_TEST(CompilationCache) {
13190 LocalContext context;
13191 v8::HandleScope scope(context->GetIsolate());
13192 v8::Handle<v8::String> source0 = v8::String::New("1234");
13193 v8::Handle<v8::String> source1 = v8::String::New("1234");
13194 v8::Handle<v8::Script> script0 =
13195 v8::Script::Compile(source0, v8::String::New("test.js"));
13196 v8::Handle<v8::Script> script1 =
13197 v8::Script::Compile(source1, v8::String::New("test.js"));
13198 v8::Handle<v8::Script> script2 =
13199 v8::Script::Compile(source0); // different origin
13200 CHECK_EQ(1234, script0->Run()->Int32Value());
13201 CHECK_EQ(1234, script1->Run()->Int32Value());
13202 CHECK_EQ(1234, script2->Run()->Int32Value());
13206 static void FunctionNameCallback(
13207 const v8::FunctionCallbackInfo<v8::Value>& args) {
13208 ApiTestFuzzer::Fuzz();
13209 args.GetReturnValue().Set(v8_num(42));
13213 THREADED_TEST(CallbackFunctionName) {
13214 LocalContext context;
13215 v8::HandleScope scope(context->GetIsolate());
13216 Local<ObjectTemplate> t = ObjectTemplate::New();
13217 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback));
13218 context->Global()->Set(v8_str("obj"), t->NewInstance());
13219 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
13220 CHECK(value->IsString());
13221 v8::String::Utf8Value name(value);
13222 CHECK_EQ("asdf", *name);
13226 THREADED_TEST(DateAccess) {
13227 LocalContext context;
13228 v8::HandleScope scope(context->GetIsolate());
13229 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0);
13230 CHECK(date->IsDate());
13231 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
13235 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) {
13236 v8::Handle<v8::Object> obj = val.As<v8::Object>();
13237 v8::Handle<v8::Array> props = obj->GetPropertyNames();
13238 CHECK_EQ(elmc, props->Length());
13239 for (int i = 0; i < elmc; i++) {
13240 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
13241 CHECK_EQ(elmv[i], *elm);
13246 void CheckOwnProperties(v8::Handle<v8::Value> val,
13248 const char* elmv[]) {
13249 v8::Handle<v8::Object> obj = val.As<v8::Object>();
13250 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
13251 CHECK_EQ(elmc, props->Length());
13252 for (int i = 0; i < elmc; i++) {
13253 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i)));
13254 CHECK_EQ(elmv[i], *elm);
13259 THREADED_TEST(PropertyEnumeration) {
13260 LocalContext context;
13261 v8::HandleScope scope(context->GetIsolate());
13262 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
13265 "result[1] = {a: 1, b: 2};"
13266 "result[2] = [1, 2, 3];"
13267 "var proto = {x: 1, y: 2, z: 3};"
13268 "var x = { __proto__: proto, w: 0, z: 1 };"
13270 "result;"))->Run();
13271 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
13272 CHECK_EQ(4, elms->Length());
13274 const char** elmv0 = NULL;
13275 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13276 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13278 const char* elmv1[] = {"a", "b"};
13279 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
13280 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1);
13282 const char* elmv2[] = {"0", "1", "2"};
13283 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
13284 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2);
13286 const char* elmv3[] = {"w", "z", "x", "y"};
13287 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3);
13289 const char* elmv4[] = {"w", "z"};
13290 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4);
13294 THREADED_TEST(PropertyEnumeration2) {
13295 LocalContext context;
13296 v8::HandleScope scope(context->GetIsolate());
13297 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New(
13300 "result[1] = {a: 1, b: 2};"
13301 "result[2] = [1, 2, 3];"
13302 "var proto = {x: 1, y: 2, z: 3};"
13303 "var x = { __proto__: proto, w: 0, z: 1 };"
13305 "result;"))->Run();
13306 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
13307 CHECK_EQ(4, elms->Length());
13309 const char** elmv0 = NULL;
13310 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0);
13312 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0));
13313 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
13314 CHECK_EQ(0, props->Length());
13315 for (uint32_t i = 0; i < props->Length(); i++) {
13316 printf("p[%d]\n", i);
13320 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
13322 v8::AccessType type,
13323 Local<Value> data) {
13324 return type != v8::ACCESS_SET;
13328 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
13330 v8::AccessType type,
13331 Local<Value> data) {
13332 return type != v8::ACCESS_SET;
13336 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
13337 LocalContext context;
13338 v8::HandleScope scope(context->GetIsolate());
13339 Local<ObjectTemplate> templ = ObjectTemplate::New();
13340 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
13341 IndexedSetAccessBlocker);
13342 templ->Set(v8_str("x"), v8::True());
13343 Local<v8::Object> instance = templ->NewInstance();
13344 context->Global()->Set(v8_str("obj"), instance);
13345 Local<Value> value = CompileRun("obj.x");
13346 CHECK(value->BooleanValue());
13350 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
13352 v8::AccessType type,
13353 Local<Value> data) {
13358 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
13360 v8::AccessType type,
13361 Local<Value> data) {
13367 THREADED_TEST(AccessChecksReenabledCorrectly) {
13368 LocalContext context;
13369 v8::HandleScope scope(context->GetIsolate());
13370 Local<ObjectTemplate> templ = ObjectTemplate::New();
13371 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13372 IndexedGetAccessBlocker);
13373 templ->Set(v8_str("a"), v8_str("a"));
13374 // Add more than 8 (see kMaxFastProperties) properties
13375 // so that the constructor will force copying map.
13376 // Cannot sprintf, gcc complains unsafety.
13378 for (char i = '0'; i <= '9' ; i++) {
13380 for (char j = '0'; j <= '9'; j++) {
13382 for (char k = '0'; k <= '9'; k++) {
13385 templ->Set(v8_str(buf), v8::Number::New(k));
13390 Local<v8::Object> instance_1 = templ->NewInstance();
13391 context->Global()->Set(v8_str("obj_1"), instance_1);
13393 Local<Value> value_1 = CompileRun("obj_1.a");
13394 CHECK(value_1->IsUndefined());
13396 Local<v8::Object> instance_2 = templ->NewInstance();
13397 context->Global()->Set(v8_str("obj_2"), instance_2);
13399 Local<Value> value_2 = CompileRun("obj_2.a");
13400 CHECK(value_2->IsUndefined());
13404 // This tests that access check information remains on the global
13405 // object template when creating contexts.
13406 THREADED_TEST(AccessControlRepeatedContextCreation) {
13407 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13408 v8::HandleScope handle_scope(isolate);
13409 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13410 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
13411 IndexedSetAccessBlocker);
13412 i::Handle<i::ObjectTemplateInfo> internal_template =
13413 v8::Utils::OpenHandle(*global_template);
13414 CHECK(!internal_template->constructor()->IsUndefined());
13415 i::Handle<i::FunctionTemplateInfo> constructor(
13416 i::FunctionTemplateInfo::cast(internal_template->constructor()));
13417 CHECK(!constructor->access_check_info()->IsUndefined());
13418 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
13419 CHECK(!context0.IsEmpty());
13420 CHECK(!constructor->access_check_info()->IsUndefined());
13424 THREADED_TEST(TurnOnAccessCheck) {
13425 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13426 v8::HandleScope handle_scope(isolate);
13428 // Create an environment with access check to the global object disabled by
13430 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13431 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
13432 IndexedGetAccessBlocker,
13433 v8::Handle<v8::Value>(),
13435 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
13436 Context::Scope context_scope(context);
13438 // Set up a property and a number of functions.
13439 context->Global()->Set(v8_str("a"), v8_num(1));
13440 CompileRun("function f1() {return a;}"
13441 "function f2() {return a;}"
13442 "function g1() {return h();}"
13443 "function g2() {return h();}"
13444 "function h() {return 1;}");
13445 Local<Function> f1 =
13446 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
13447 Local<Function> f2 =
13448 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
13449 Local<Function> g1 =
13450 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
13451 Local<Function> g2 =
13452 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
13453 Local<Function> h =
13454 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
13456 // Get the global object.
13457 v8::Handle<v8::Object> global = context->Global();
13459 // Call f1 one time and f2 a number of times. This will ensure that f1 still
13460 // uses the runtime system to retreive property a whereas f2 uses global load
13462 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
13463 for (int i = 0; i < 4; i++) {
13464 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
13467 // Same for g1 and g2.
13468 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
13469 for (int i = 0; i < 4; i++) {
13470 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
13473 // Detach the global and turn on access check.
13474 context->DetachGlobal();
13475 context->Global()->TurnOnAccessCheck();
13477 // Failing access check to property get results in undefined.
13478 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
13479 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
13481 // Failing access check to function call results in exception.
13482 CHECK(g1->Call(global, 0, NULL).IsEmpty());
13483 CHECK(g2->Call(global, 0, NULL).IsEmpty());
13485 // No failing access check when just returning a constant.
13486 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
13490 static const char* kPropertyA = "a";
13491 static const char* kPropertyH = "h";
13493 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
13495 v8::AccessType type,
13496 Local<Value> data) {
13497 if (!name->IsString()) return false;
13498 i::Handle<i::String> name_handle =
13499 v8::Utils::OpenHandle(String::Cast(*name));
13500 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
13501 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
13505 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
13506 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13507 v8::HandleScope handle_scope(isolate);
13509 // Create an environment with access check to the global object disabled by
13510 // default. When the registered access checker will block access to properties
13512 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
13513 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
13514 IndexedGetAccessBlocker,
13515 v8::Handle<v8::Value>(),
13517 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
13518 Context::Scope context_scope(context);
13520 // Set up a property and a number of functions.
13521 context->Global()->Set(v8_str("a"), v8_num(1));
13522 static const char* source = "function f1() {return a;}"
13523 "function f2() {return a;}"
13524 "function g1() {return h();}"
13525 "function g2() {return h();}"
13526 "function h() {return 1;}";
13528 CompileRun(source);
13529 Local<Function> f1;
13530 Local<Function> f2;
13531 Local<Function> g1;
13532 Local<Function> g2;
13534 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
13535 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
13536 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
13537 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
13538 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
13540 // Get the global object.
13541 v8::Handle<v8::Object> global = context->Global();
13543 // Call f1 one time and f2 a number of times. This will ensure that f1 still
13544 // uses the runtime system to retreive property a whereas f2 uses global load
13546 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
13547 for (int i = 0; i < 4; i++) {
13548 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
13551 // Same for g1 and g2.
13552 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
13553 for (int i = 0; i < 4; i++) {
13554 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
13557 // Detach the global and turn on access check now blocking access to property
13558 // a and function h.
13559 context->DetachGlobal();
13560 context->Global()->TurnOnAccessCheck();
13562 // Failing access check to property get results in undefined.
13563 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
13564 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
13566 // Failing access check to function call results in exception.
13567 CHECK(g1->Call(global, 0, NULL).IsEmpty());
13568 CHECK(g2->Call(global, 0, NULL).IsEmpty());
13570 // No failing access check when just returning a constant.
13571 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
13573 // Now compile the source again. And get the newly compiled functions, except
13574 // for h for which access is blocked.
13575 CompileRun(source);
13576 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
13577 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
13578 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
13579 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
13580 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
13582 // Failing access check to property get results in undefined.
13583 CHECK(f1->Call(global, 0, NULL)->IsUndefined());
13584 CHECK(f2->Call(global, 0, NULL)->IsUndefined());
13586 // Failing access check to function call results in exception.
13587 CHECK(g1->Call(global, 0, NULL).IsEmpty());
13588 CHECK(g2->Call(global, 0, NULL).IsEmpty());
13592 // This test verifies that pre-compilation (aka preparsing) can be called
13593 // without initializing the whole VM. Thus we cannot run this test in a
13594 // multi-threaded setup.
13596 // TODO(155): This test would break without the initialization of V8. This is
13597 // a workaround for now to make this test not fail.
13598 v8::V8::Initialize();
13599 const char* script = "function foo(a) { return a+1; }";
13600 v8::ScriptData* sd =
13601 v8::ScriptData::PreCompile(script, i::StrLength(script));
13602 CHECK_NE(sd->Length(), 0);
13603 CHECK_NE(sd->Data(), NULL);
13604 CHECK(!sd->HasError());
13609 TEST(PreCompileWithError) {
13610 v8::V8::Initialize();
13611 const char* script = "function foo(a) { return 1 * * 2; }";
13612 v8::ScriptData* sd =
13613 v8::ScriptData::PreCompile(script, i::StrLength(script));
13614 CHECK(sd->HasError());
13619 TEST(Regress31661) {
13620 v8::V8::Initialize();
13621 const char* script = " The Definintive Guide";
13622 v8::ScriptData* sd =
13623 v8::ScriptData::PreCompile(script, i::StrLength(script));
13624 CHECK(sd->HasError());
13629 // Tests that ScriptData can be serialized and deserialized.
13630 TEST(PreCompileSerialization) {
13631 v8::V8::Initialize();
13632 const char* script = "function foo(a) { return a+1; }";
13633 v8::ScriptData* sd =
13634 v8::ScriptData::PreCompile(script, i::StrLength(script));
13637 int serialized_data_length = sd->Length();
13638 char* serialized_data = i::NewArray<char>(serialized_data_length);
13639 i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
13642 v8::ScriptData* deserialized_sd =
13643 v8::ScriptData::New(serialized_data, serialized_data_length);
13645 // Verify that the original is the same as the deserialized.
13646 CHECK_EQ(sd->Length(), deserialized_sd->Length());
13647 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
13648 CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
13651 delete deserialized_sd;
13655 // Attempts to deserialize bad data.
13656 TEST(PreCompileDeserializationError) {
13657 v8::V8::Initialize();
13658 const char* data = "DONT CARE";
13659 int invalid_size = 3;
13660 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size);
13662 CHECK_EQ(0, sd->Length());
13668 // Attempts to deserialize bad data.
13669 TEST(PreCompileInvalidPreparseDataError) {
13670 v8::V8::Initialize();
13671 LocalContext context;
13672 v8::HandleScope scope(context->GetIsolate());
13674 const char* script = "function foo(){ return 5;}\n"
13675 "function bar(){ return 6 + 7;} foo();";
13676 v8::ScriptData* sd =
13677 v8::ScriptData::PreCompile(script, i::StrLength(script));
13678 CHECK(!sd->HasError());
13679 // ScriptDataImpl private implementation details
13680 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
13681 const int kFunctionEntrySize = i::FunctionEntry::kSize;
13682 const int kFunctionEntryStartOffset = 0;
13683 const int kFunctionEntryEndOffset = 1;
13684 unsigned* sd_data =
13685 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
13687 // Overwrite function bar's end position with 0.
13688 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
13689 v8::TryCatch try_catch;
13691 Local<String> source = String::New(script);
13692 Local<Script> compiled_script = Script::New(source, NULL, sd);
13693 CHECK(try_catch.HasCaught());
13694 String::Utf8Value exception_value(try_catch.Message()->Get());
13695 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar",
13700 // Overwrite function bar's start position with 200. The function entry
13701 // will not be found when searching for it by position and we should fall
13702 // back on eager compilation.
13703 sd = v8::ScriptData::PreCompile(script, i::StrLength(script));
13704 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
13705 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
13707 compiled_script = Script::New(source, NULL, sd);
13708 CHECK(!try_catch.HasCaught());
13714 // Verifies that the Handle<String> and const char* versions of the API produce
13715 // the same results (at least for one trivial case).
13716 TEST(PreCompileAPIVariationsAreSame) {
13717 v8::V8::Initialize();
13718 v8::HandleScope scope(v8::Isolate::GetCurrent());
13720 const char* cstring = "function foo(a) { return a+1; }";
13722 v8::ScriptData* sd_from_cstring =
13723 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
13725 TestAsciiResource* resource = new TestAsciiResource(cstring);
13726 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile(
13727 v8::String::NewExternal(resource));
13729 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile(
13730 v8::String::New(cstring));
13732 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length());
13733 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
13734 sd_from_external_string->Data(),
13735 sd_from_cstring->Length()));
13737 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length());
13738 CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
13739 sd_from_string->Data(),
13740 sd_from_cstring->Length()));
13743 delete sd_from_cstring;
13744 delete sd_from_external_string;
13745 delete sd_from_string;
13749 // This tests that we do not allow dictionary load/call inline caches
13750 // to use functions that have not yet been compiled. The potential
13751 // problem of loading a function that has not yet been compiled can
13752 // arise because we share code between contexts via the compilation
13754 THREADED_TEST(DictionaryICLoadedFunction) {
13755 v8::HandleScope scope(v8::Isolate::GetCurrent());
13757 for (int i = 0; i < 2; i++) {
13758 LocalContext context;
13759 context->Global()->Set(v8_str("tmp"), v8::True());
13760 context->Global()->Delete(v8_str("tmp"));
13761 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
13764 for (int i = 0; i < 2; i++) {
13765 LocalContext context;
13766 context->Global()->Set(v8_str("tmp"), v8::True());
13767 context->Global()->Delete(v8_str("tmp"));
13768 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
13773 // Test that cross-context new calls use the context of the callee to
13774 // create the new JavaScript object.
13775 THREADED_TEST(CrossContextNew) {
13776 v8::Isolate* isolate = v8::Isolate::GetCurrent();
13777 v8::HandleScope scope(isolate);
13778 v8::Local<Context> context0 = Context::New(isolate);
13779 v8::Local<Context> context1 = Context::New(isolate);
13781 // Allow cross-domain access.
13782 Local<String> token = v8_str("<security token>");
13783 context0->SetSecurityToken(token);
13784 context1->SetSecurityToken(token);
13786 // Set an 'x' property on the Object prototype and define a
13787 // constructor function in context0.
13789 CompileRun("Object.prototype.x = 42; function C() {};");
13792 // Call the constructor function from context0 and check that the
13793 // result has the 'x' property.
13795 context1->Global()->Set(v8_str("other"), context0->Global());
13796 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
13797 CHECK(value->IsInt32());
13798 CHECK_EQ(42, value->Int32Value());
13803 class RegExpInterruptTest {
13805 RegExpInterruptTest() : block_(NULL) {}
13806 ~RegExpInterruptTest() { delete block_; }
13808 block_ = i::OS::CreateSemaphore(0);
13810 gc_during_regexp_ = 0;
13811 regexp_success_ = false;
13812 gc_success_ = false;
13813 GCThread gc_thread(this);
13815 v8::Locker::StartPreemption(1);
13817 LongRunningRegExp();
13819 v8::Unlocker unlock(CcTest::default_isolate());
13822 v8::Locker::StopPreemption();
13823 CHECK(regexp_success_);
13824 CHECK(gc_success_);
13828 // Number of garbage collections required.
13829 static const int kRequiredGCs = 5;
13831 class GCThread : public i::Thread {
13833 explicit GCThread(RegExpInterruptTest* test)
13834 : Thread("GCThread"), test_(test) {}
13835 virtual void Run() {
13836 test_->CollectGarbage();
13839 RegExpInterruptTest* test_;
13842 void CollectGarbage() {
13844 while (gc_during_regexp_ < kRequiredGCs) {
13846 v8::Locker lock(CcTest::default_isolate());
13847 // TODO(lrn): Perhaps create some garbage before collecting.
13848 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13853 gc_success_ = true;
13856 void LongRunningRegExp() {
13857 block_->Signal(); // Enable garbage collection thread on next preemption.
13859 while (gc_during_regexp_ < kRequiredGCs) {
13860 int gc_before = gc_count_;
13862 // Match 15-30 "a"'s against 14 and a "b".
13863 const char* c_source =
13864 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
13865 ".exec('aaaaaaaaaaaaaaab') === null";
13866 Local<String> source = String::New(c_source);
13867 Local<Script> script = Script::Compile(source);
13868 Local<Value> result = script->Run();
13869 if (!result->BooleanValue()) {
13870 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit.
13875 // Match 15-30 "a"'s against 15 and a "b".
13876 const char* c_source =
13877 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
13878 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'";
13879 Local<String> source = String::New(c_source);
13880 Local<Script> script = Script::Compile(source);
13881 Local<Value> result = script->Run();
13882 if (!result->BooleanValue()) {
13883 gc_during_regexp_ = kRequiredGCs;
13887 int gc_after = gc_count_;
13888 gc_during_regexp_ += gc_after - gc_before;
13892 regexp_success_ = true;
13895 i::Semaphore* block_;
13897 int gc_during_regexp_;
13898 bool regexp_success_;
13903 // Test that a regular expression execution can be interrupted and
13904 // survive a garbage collection.
13905 TEST(RegExpInterruption) {
13906 v8::Locker lock(CcTest::default_isolate());
13907 v8::V8::Initialize();
13908 v8::HandleScope scope(CcTest::default_isolate());
13909 Local<Context> local_env;
13912 local_env = env.local();
13915 // Local context should still be live.
13916 CHECK(!local_env.IsEmpty());
13917 local_env->Enter();
13919 // Should complete without problems.
13920 RegExpInterruptTest().RunTest();
13926 class ApplyInterruptTest {
13928 ApplyInterruptTest() : block_(NULL) {}
13929 ~ApplyInterruptTest() { delete block_; }
13931 block_ = i::OS::CreateSemaphore(0);
13933 gc_during_apply_ = 0;
13934 apply_success_ = false;
13935 gc_success_ = false;
13936 GCThread gc_thread(this);
13938 v8::Locker::StartPreemption(1);
13940 LongRunningApply();
13942 v8::Unlocker unlock(CcTest::default_isolate());
13945 v8::Locker::StopPreemption();
13946 CHECK(apply_success_);
13947 CHECK(gc_success_);
13951 // Number of garbage collections required.
13952 static const int kRequiredGCs = 2;
13954 class GCThread : public i::Thread {
13956 explicit GCThread(ApplyInterruptTest* test)
13957 : Thread("GCThread"), test_(test) {}
13958 virtual void Run() {
13959 test_->CollectGarbage();
13962 ApplyInterruptTest* test_;
13965 void CollectGarbage() {
13967 while (gc_during_apply_ < kRequiredGCs) {
13969 v8::Locker lock(CcTest::default_isolate());
13970 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
13975 gc_success_ = true;
13978 void LongRunningApply() {
13981 while (gc_during_apply_ < kRequiredGCs) {
13982 int gc_before = gc_count_;
13984 const char* c_source =
13985 "function do_very_little(bar) {"
13988 "for (var i = 0; i < 100000; i++) {"
13989 " do_very_little.apply(this, ['bar']);"
13991 Local<String> source = String::New(c_source);
13992 Local<Script> script = Script::Compile(source);
13993 Local<Value> result = script->Run();
13994 // Check that no exception was thrown.
13995 CHECK(!result.IsEmpty());
13997 int gc_after = gc_count_;
13998 gc_during_apply_ += gc_after - gc_before;
14001 apply_success_ = true;
14004 i::Semaphore* block_;
14006 int gc_during_apply_;
14007 bool apply_success_;
14012 // Test that nothing bad happens if we get a preemption just when we were
14013 // about to do an apply().
14014 TEST(ApplyInterruption) {
14015 v8::Locker lock(CcTest::default_isolate());
14016 v8::V8::Initialize();
14017 v8::HandleScope scope(CcTest::default_isolate());
14018 Local<Context> local_env;
14021 local_env = env.local();
14024 // Local context should still be live.
14025 CHECK(!local_env.IsEmpty());
14026 local_env->Enter();
14028 // Should complete without problems.
14029 ApplyInterruptTest().RunTest();
14035 // Verify that we can clone an object
14036 TEST(ObjectClone) {
14038 v8::HandleScope scope(env->GetIsolate());
14040 const char* sample =
14042 "rv.alpha = 'hello';" \
14046 // Create an object, verify basics.
14047 Local<Value> val = CompileRun(sample);
14048 CHECK(val->IsObject());
14049 Local<v8::Object> obj = val.As<v8::Object>();
14050 obj->Set(v8_str("gamma"), v8_str("cloneme"));
14052 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
14053 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
14054 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
14057 Local<v8::Object> clone = obj->Clone();
14058 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
14059 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta")));
14060 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
14062 // Set a property on the clone, verify each object.
14063 clone->Set(v8_str("beta"), v8::Integer::New(456));
14064 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta")));
14065 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta")));
14069 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource {
14071 explicit AsciiVectorResource(i::Vector<const char> vector)
14073 virtual ~AsciiVectorResource() {}
14074 virtual size_t length() const { return data_.length(); }
14075 virtual const char* data() const { return data_.start(); }
14077 i::Vector<const char> data_;
14081 class UC16VectorResource : public v8::String::ExternalStringResource {
14083 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
14085 virtual ~UC16VectorResource() {}
14086 virtual size_t length() const { return data_.length(); }
14087 virtual const i::uc16* data() const { return data_.start(); }
14089 i::Vector<const i::uc16> data_;
14093 static void MorphAString(i::String* string,
14094 AsciiVectorResource* ascii_resource,
14095 UC16VectorResource* uc16_resource) {
14096 CHECK(i::StringShape(string).IsExternal());
14097 if (string->IsOneByteRepresentation()) {
14098 // Check old map is not internalized or long.
14099 CHECK(string->map() == HEAP->external_ascii_string_map());
14100 // Morph external string to be TwoByte string.
14101 string->set_map(HEAP->external_string_map());
14102 i::ExternalTwoByteString* morphed =
14103 i::ExternalTwoByteString::cast(string);
14104 morphed->set_resource(uc16_resource);
14106 // Check old map is not internalized or long.
14107 CHECK(string->map() == HEAP->external_string_map());
14108 // Morph external string to be ASCII string.
14109 string->set_map(HEAP->external_ascii_string_map());
14110 i::ExternalAsciiString* morphed =
14111 i::ExternalAsciiString::cast(string);
14112 morphed->set_resource(ascii_resource);
14117 // Test that we can still flatten a string if the components it is built up
14118 // from have been turned into 16 bit strings in the mean time.
14119 THREADED_TEST(MorphCompositeStringTest) {
14120 char utf_buffer[129];
14121 const char* c_string = "Now is the time for all good men"
14122 " to come to the aid of the party";
14123 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
14126 i::Factory* factory = i::Isolate::Current()->factory();
14127 v8::HandleScope scope(env->GetIsolate());
14128 AsciiVectorResource ascii_resource(
14129 i::Vector<const char>(c_string, i::StrLength(c_string)));
14130 UC16VectorResource uc16_resource(
14131 i::Vector<const uint16_t>(two_byte_string,
14132 i::StrLength(c_string)));
14134 Local<String> lhs(v8::Utils::ToLocal(
14135 factory->NewExternalStringFromAscii(&ascii_resource)));
14136 Local<String> rhs(v8::Utils::ToLocal(
14137 factory->NewExternalStringFromAscii(&ascii_resource)));
14139 env->Global()->Set(v8_str("lhs"), lhs);
14140 env->Global()->Set(v8_str("rhs"), rhs);
14143 "var cons = lhs + rhs;"
14144 "var slice = lhs.substring(1, lhs.length - 1);"
14145 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
14147 CHECK(lhs->IsOneByte());
14148 CHECK(rhs->IsOneByte());
14150 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource);
14151 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource);
14153 // This should UTF-8 without flattening, since everything is ASCII.
14154 Handle<String> cons = v8_compile("cons")->Run().As<String>();
14155 CHECK_EQ(128, cons->Utf8Length());
14157 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
14158 CHECK_EQ(128, nchars);
14159 CHECK_EQ(0, strcmp(
14161 "Now is the time for all good men to come to the aid of the party"
14162 "Now is the time for all good men to come to the aid of the party"));
14164 // Now do some stuff to make sure the strings are flattened, etc.
14166 "/[^a-z]/.test(cons);"
14167 "/[^a-z]/.test(slice);"
14168 "/[^a-z]/.test(slice_on_cons);");
14169 const char* expected_cons =
14170 "Now is the time for all good men to come to the aid of the party"
14171 "Now is the time for all good men to come to the aid of the party";
14172 const char* expected_slice =
14173 "ow is the time for all good men to come to the aid of the part";
14174 const char* expected_slice_on_cons =
14175 "ow is the time for all good men to come to the aid of the party"
14176 "Now is the time for all good men to come to the aid of the part";
14177 CHECK_EQ(String::New(expected_cons),
14178 env->Global()->Get(v8_str("cons")));
14179 CHECK_EQ(String::New(expected_slice),
14180 env->Global()->Get(v8_str("slice")));
14181 CHECK_EQ(String::New(expected_slice_on_cons),
14182 env->Global()->Get(v8_str("slice_on_cons")));
14184 i::DeleteArray(two_byte_string);
14188 TEST(CompileExternalTwoByteSource) {
14189 LocalContext context;
14190 v8::HandleScope scope(context->GetIsolate());
14192 // This is a very short list of sources, which currently is to check for a
14193 // regression caused by r2703.
14194 const char* ascii_sources[] = {
14196 "-0.5", // This mainly testes PushBack in the Scanner.
14197 "--0.5", // This mainly testes PushBack in the Scanner.
14201 // Compile the sources as external two byte strings.
14202 for (int i = 0; ascii_sources[i] != NULL; i++) {
14203 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]);
14204 UC16VectorResource uc16_resource(
14205 i::Vector<const uint16_t>(two_byte_string,
14206 i::StrLength(ascii_sources[i])));
14207 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource);
14208 v8::Script::Compile(source);
14209 i::DeleteArray(two_byte_string);
14214 class RegExpStringModificationTest {
14216 RegExpStringModificationTest()
14217 : block_(i::OS::CreateSemaphore(0)),
14219 morphs_during_regexp_(0),
14220 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)),
14221 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {}
14222 ~RegExpStringModificationTest() { delete block_; }
14224 i::Factory* factory = i::Isolate::Current()->factory();
14226 regexp_success_ = false;
14227 morph_success_ = false;
14229 // Initialize the contents of two_byte_content_ to be a uc16 representation
14230 // of "aaaaaaaaaaaaaab".
14231 for (int i = 0; i < 14; i++) {
14232 two_byte_content_[i] = 'a';
14234 two_byte_content_[14] = 'b';
14236 // Create the input string for the regexp - the one we are going to change
14238 input_ = factory->NewExternalStringFromAscii(&ascii_resource_);
14240 // Inject the input as a global variable.
14241 i::Handle<i::String> input_name =
14242 factory->NewStringFromAscii(i::Vector<const char>("input", 5));
14243 i::Isolate::Current()->native_context()->global_object()->SetProperty(
14247 i::kNonStrictMode)->ToObjectChecked();
14249 MorphThread morph_thread(this);
14250 morph_thread.Start();
14251 v8::Locker::StartPreemption(1);
14252 LongRunningRegExp();
14254 v8::Unlocker unlock(CcTest::default_isolate());
14255 morph_thread.Join();
14257 v8::Locker::StopPreemption();
14258 CHECK(regexp_success_);
14259 CHECK(morph_success_);
14263 // Number of string modifications required.
14264 static const int kRequiredModifications = 5;
14265 static const int kMaxModifications = 100;
14267 class MorphThread : public i::Thread {
14269 explicit MorphThread(RegExpStringModificationTest* test)
14270 : Thread("MorphThread"), test_(test) {}
14271 virtual void Run() {
14272 test_->MorphString();
14275 RegExpStringModificationTest* test_;
14278 void MorphString() {
14280 while (morphs_during_regexp_ < kRequiredModifications &&
14281 morphs_ < kMaxModifications) {
14283 v8::Locker lock(CcTest::default_isolate());
14284 // Swap string between ascii and two-byte representation.
14285 i::String* string = *input_;
14286 MorphAString(string, &ascii_resource_, &uc16_resource_);
14291 morph_success_ = true;
14294 void LongRunningRegExp() {
14295 block_->Signal(); // Enable morphing thread on next preemption.
14296 while (morphs_during_regexp_ < kRequiredModifications &&
14297 morphs_ < kMaxModifications) {
14298 int morphs_before = morphs_;
14300 v8::HandleScope scope(v8::Isolate::GetCurrent());
14301 // Match 15-30 "a"'s against 14 and a "b".
14302 const char* c_source =
14303 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/"
14304 ".exec(input) === null";
14305 Local<String> source = String::New(c_source);
14306 Local<Script> script = Script::Compile(source);
14307 Local<Value> result = script->Run();
14308 CHECK(result->IsTrue());
14310 int morphs_after = morphs_;
14311 morphs_during_regexp_ += morphs_after - morphs_before;
14313 regexp_success_ = true;
14316 i::uc16 two_byte_content_[15];
14317 i::Semaphore* block_;
14319 int morphs_during_regexp_;
14320 bool regexp_success_;
14321 bool morph_success_;
14322 i::Handle<i::String> input_;
14323 AsciiVectorResource ascii_resource_;
14324 UC16VectorResource uc16_resource_;
14328 // Test that a regular expression execution can be interrupted and
14329 // the string changed without failing.
14330 TEST(RegExpStringModification) {
14331 v8::Locker lock(CcTest::default_isolate());
14332 v8::V8::Initialize();
14333 v8::HandleScope scope(CcTest::default_isolate());
14334 Local<Context> local_env;
14337 local_env = env.local();
14340 // Local context should still be live.
14341 CHECK(!local_env.IsEmpty());
14342 local_env->Enter();
14344 // Should complete without problems.
14345 RegExpStringModificationTest().RunTest();
14351 // Test that we cannot set a property on the global object if there
14352 // is a read-only property in the prototype chain.
14353 TEST(ReadOnlyPropertyInGlobalProto) {
14354 i::FLAG_es5_readonly = true;
14355 v8::HandleScope scope(v8::Isolate::GetCurrent());
14356 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14357 LocalContext context(0, templ);
14358 v8::Handle<v8::Object> global = context->Global();
14359 v8::Handle<v8::Object> global_proto =
14360 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
14361 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly);
14362 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly);
14363 // Check without 'eval' or 'with'.
14364 v8::Handle<v8::Value> res =
14365 CompileRun("function f() { x = 42; return x; }; f()");
14366 CHECK_EQ(v8::Integer::New(0), res);
14367 // Check with 'eval'.
14368 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
14369 CHECK_EQ(v8::Integer::New(0), res);
14370 // Check with 'with'.
14371 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
14372 CHECK_EQ(v8::Integer::New(0), res);
14375 static int force_set_set_count = 0;
14376 static int force_set_get_count = 0;
14377 bool pass_on_get = false;
14379 static void ForceSetGetter(v8::Local<v8::String> name,
14380 const v8::PropertyCallbackInfo<v8::Value>& info) {
14381 force_set_get_count++;
14385 info.GetReturnValue().Set(3);
14388 static void ForceSetSetter(v8::Local<v8::String> name,
14389 v8::Local<v8::Value> value,
14390 const v8::PropertyCallbackInfo<void>& info) {
14391 force_set_set_count++;
14394 static void ForceSetInterceptSetter(
14395 v8::Local<v8::String> name,
14396 v8::Local<v8::Value> value,
14397 const v8::PropertyCallbackInfo<v8::Value>& info) {
14398 force_set_set_count++;
14399 info.GetReturnValue().SetUndefined();
14404 force_set_get_count = 0;
14405 force_set_set_count = 0;
14406 pass_on_get = false;
14408 v8::HandleScope scope(v8::Isolate::GetCurrent());
14409 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14410 v8::Handle<v8::String> access_property = v8::String::New("a");
14411 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
14412 LocalContext context(NULL, templ);
14413 v8::Handle<v8::Object> global = context->Global();
14415 // Ordinary properties
14416 v8::Handle<v8::String> simple_property = v8::String::New("p");
14417 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly);
14418 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14419 // This should fail because the property is read-only
14420 global->Set(simple_property, v8::Int32::New(5));
14421 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14422 // This should succeed even though the property is read-only
14423 global->ForceSet(simple_property, v8::Int32::New(6));
14424 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
14427 CHECK_EQ(0, force_set_set_count);
14428 CHECK_EQ(0, force_set_get_count);
14429 CHECK_EQ(3, global->Get(access_property)->Int32Value());
14430 // CHECK_EQ the property shouldn't override it, just call the setter
14431 // which in this case does nothing.
14432 global->Set(access_property, v8::Int32::New(7));
14433 CHECK_EQ(3, global->Get(access_property)->Int32Value());
14434 CHECK_EQ(1, force_set_set_count);
14435 CHECK_EQ(2, force_set_get_count);
14436 // Forcing the property to be set should override the accessor without
14438 global->ForceSet(access_property, v8::Int32::New(8));
14439 CHECK_EQ(8, global->Get(access_property)->Int32Value());
14440 CHECK_EQ(1, force_set_set_count);
14441 CHECK_EQ(2, force_set_get_count);
14445 TEST(ForceSetWithInterceptor) {
14446 force_set_get_count = 0;
14447 force_set_set_count = 0;
14448 pass_on_get = false;
14450 v8::HandleScope scope(v8::Isolate::GetCurrent());
14451 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14452 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
14453 LocalContext context(NULL, templ);
14454 v8::Handle<v8::Object> global = context->Global();
14456 v8::Handle<v8::String> some_property = v8::String::New("a");
14457 CHECK_EQ(0, force_set_set_count);
14458 CHECK_EQ(0, force_set_get_count);
14459 CHECK_EQ(3, global->Get(some_property)->Int32Value());
14460 // Setting the property shouldn't override it, just call the setter
14461 // which in this case does nothing.
14462 global->Set(some_property, v8::Int32::New(7));
14463 CHECK_EQ(3, global->Get(some_property)->Int32Value());
14464 CHECK_EQ(1, force_set_set_count);
14465 CHECK_EQ(2, force_set_get_count);
14466 // Getting the property when the interceptor returns an empty handle
14467 // should yield undefined, since the property isn't present on the
14468 // object itself yet.
14469 pass_on_get = true;
14470 CHECK(global->Get(some_property)->IsUndefined());
14471 CHECK_EQ(1, force_set_set_count);
14472 CHECK_EQ(3, force_set_get_count);
14473 // Forcing the property to be set should cause the value to be
14474 // set locally without calling the interceptor.
14475 global->ForceSet(some_property, v8::Int32::New(8));
14476 CHECK_EQ(8, global->Get(some_property)->Int32Value());
14477 CHECK_EQ(1, force_set_set_count);
14478 CHECK_EQ(4, force_set_get_count);
14479 // Reenabling the interceptor should cause it to take precedence over
14481 pass_on_get = false;
14482 CHECK_EQ(3, global->Get(some_property)->Int32Value());
14483 CHECK_EQ(1, force_set_set_count);
14484 CHECK_EQ(5, force_set_get_count);
14485 // The interceptor should also work for other properties
14486 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value());
14487 CHECK_EQ(1, force_set_set_count);
14488 CHECK_EQ(6, force_set_get_count);
14492 THREADED_TEST(ForceDelete) {
14493 v8::HandleScope scope(v8::Isolate::GetCurrent());
14494 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14495 LocalContext context(NULL, templ);
14496 v8::Handle<v8::Object> global = context->Global();
14498 // Ordinary properties
14499 v8::Handle<v8::String> simple_property = v8::String::New("p");
14500 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete);
14501 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14502 // This should fail because the property is dont-delete.
14503 CHECK(!global->Delete(simple_property));
14504 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
14505 // This should succeed even though the property is dont-delete.
14506 CHECK(global->ForceDelete(simple_property));
14507 CHECK(global->Get(simple_property)->IsUndefined());
14511 static int force_delete_interceptor_count = 0;
14512 static bool pass_on_delete = false;
14515 static void ForceDeleteDeleter(
14516 v8::Local<v8::String> name,
14517 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
14518 force_delete_interceptor_count++;
14519 if (pass_on_delete) return;
14520 info.GetReturnValue().Set(true);
14524 THREADED_TEST(ForceDeleteWithInterceptor) {
14525 force_delete_interceptor_count = 0;
14526 pass_on_delete = false;
14528 v8::HandleScope scope(v8::Isolate::GetCurrent());
14529 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
14530 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
14531 LocalContext context(NULL, templ);
14532 v8::Handle<v8::Object> global = context->Global();
14534 v8::Handle<v8::String> some_property = v8::String::New("a");
14535 global->Set(some_property, v8::Integer::New(42), v8::DontDelete);
14537 // Deleting a property should get intercepted and nothing should
14539 CHECK_EQ(0, force_delete_interceptor_count);
14540 CHECK(global->Delete(some_property));
14541 CHECK_EQ(1, force_delete_interceptor_count);
14542 CHECK_EQ(42, global->Get(some_property)->Int32Value());
14543 // Deleting the property when the interceptor returns an empty
14544 // handle should not delete the property since it is DontDelete.
14545 pass_on_delete = true;
14546 CHECK(!global->Delete(some_property));
14547 CHECK_EQ(2, force_delete_interceptor_count);
14548 CHECK_EQ(42, global->Get(some_property)->Int32Value());
14549 // Forcing the property to be deleted should delete the value
14550 // without calling the interceptor.
14551 CHECK(global->ForceDelete(some_property));
14552 CHECK(global->Get(some_property)->IsUndefined());
14553 CHECK_EQ(2, force_delete_interceptor_count);
14557 // Make sure that forcing a delete invalidates any IC stubs, so we
14558 // don't read the hole value.
14559 THREADED_TEST(ForceDeleteIC) {
14560 LocalContext context;
14561 v8::HandleScope scope(context->GetIsolate());
14562 // Create a DontDelete variable on the global object.
14563 CompileRun("this.__proto__ = { foo: 'horse' };"
14564 "var foo = 'fish';"
14565 "function f() { return foo.length; }");
14566 // Initialize the IC for foo in f.
14567 CompileRun("for (var i = 0; i < 4; i++) f();");
14568 // Make sure the value of foo is correct before the deletion.
14569 CHECK_EQ(4, CompileRun("f()")->Int32Value());
14570 // Force the deletion of foo.
14571 CHECK(context->Global()->ForceDelete(v8_str("foo")));
14572 // Make sure the value for foo is read from the prototype, and that
14573 // we don't get in trouble with reading the deleted cell value
14575 CHECK_EQ(5, CompileRun("f()")->Int32Value());
14579 TEST(InlinedFunctionAcrossContexts) {
14580 i::FLAG_allow_natives_syntax = true;
14581 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14582 v8::HandleScope outer_scope(isolate);
14583 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
14584 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
14588 v8::HandleScope inner_scope(v8::Isolate::GetCurrent());
14589 CompileRun("var G = 42; function foo() { return G; }");
14590 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
14592 ctx2->Global()->Set(v8_str("o"), foo);
14593 v8::Local<v8::Value> res = CompileRun(
14594 "function f() { return o(); }"
14595 "for (var i = 0; i < 10; ++i) f();"
14596 "%OptimizeFunctionOnNextCall(f);"
14598 CHECK_EQ(42, res->Int32Value());
14600 v8::Handle<v8::String> G_property = v8::String::New("G");
14601 CHECK(ctx1->Global()->ForceDelete(G_property));
14608 " return e.toString();"
14611 "ReferenceError: G is not defined");
14618 static v8::Local<Context> calling_context0;
14619 static v8::Local<Context> calling_context1;
14620 static v8::Local<Context> calling_context2;
14623 // Check that the call to the callback is initiated in
14624 // calling_context2, the directly calling context is calling_context1
14625 // and the callback itself is in calling_context0.
14626 static void GetCallingContextCallback(
14627 const v8::FunctionCallbackInfo<v8::Value>& args) {
14628 ApiTestFuzzer::Fuzz();
14629 CHECK(Context::GetCurrent() == calling_context0);
14630 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
14631 CHECK(Context::GetCalling() == calling_context1);
14632 CHECK(Context::GetEntered() == calling_context2);
14633 args.GetReturnValue().Set(42);
14637 THREADED_TEST(GetCurrentContextWhenNotInContext) {
14638 i::Isolate* isolate = i::Isolate::Current();
14639 CHECK(isolate != NULL);
14640 CHECK(isolate->context() == NULL);
14641 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
14642 v8::HandleScope scope(v8_isolate);
14643 // The following should not crash, but return an empty handle.
14644 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
14645 CHECK(current.IsEmpty());
14649 THREADED_TEST(GetCallingContext) {
14650 v8::Isolate* isolate = v8::Isolate::GetCurrent();
14651 v8::HandleScope scope(isolate);
14653 Local<Context> calling_context0(Context::New(isolate));
14654 Local<Context> calling_context1(Context::New(isolate));
14655 Local<Context> calling_context2(Context::New(isolate));
14656 ::calling_context0 = calling_context0;
14657 ::calling_context1 = calling_context1;
14658 ::calling_context2 = calling_context2;
14660 // Allow cross-domain access.
14661 Local<String> token = v8_str("<security token>");
14662 calling_context0->SetSecurityToken(token);
14663 calling_context1->SetSecurityToken(token);
14664 calling_context2->SetSecurityToken(token);
14666 // Create an object with a C++ callback in context0.
14667 calling_context0->Enter();
14668 Local<v8::FunctionTemplate> callback_templ =
14669 v8::FunctionTemplate::New(GetCallingContextCallback);
14670 calling_context0->Global()->Set(v8_str("callback"),
14671 callback_templ->GetFunction());
14672 calling_context0->Exit();
14674 // Expose context0 in context1 and set up a function that calls the
14675 // callback function.
14676 calling_context1->Enter();
14677 calling_context1->Global()->Set(v8_str("context0"),
14678 calling_context0->Global());
14679 CompileRun("function f() { context0.callback() }");
14680 calling_context1->Exit();
14682 // Expose context1 in context2 and call the callback function in
14683 // context0 indirectly through f in context1.
14684 calling_context2->Enter();
14685 calling_context2->Global()->Set(v8_str("context1"),
14686 calling_context1->Global());
14687 CompileRun("context1.f()");
14688 calling_context2->Exit();
14689 ::calling_context0.Clear();
14690 ::calling_context1.Clear();
14691 ::calling_context2.Clear();
14695 // Check that a variable declaration with no explicit initialization
14696 // value does shadow an existing property in the prototype chain.
14697 THREADED_TEST(InitGlobalVarInProtoChain) {
14698 i::FLAG_es52_globals = true;
14699 LocalContext context;
14700 v8::HandleScope scope(context->GetIsolate());
14701 // Introduce a variable in the prototype chain.
14702 CompileRun("__proto__.x = 42");
14703 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
14704 CHECK(!result->IsUndefined());
14705 CHECK_EQ(43, result->Int32Value());
14709 // Regression test for issue 398.
14710 // If a function is added to an object, creating a constant function
14711 // field, and the result is cloned, replacing the constant function on the
14712 // original should not affect the clone.
14713 // See http://code.google.com/p/v8/issues/detail?id=398
14714 THREADED_TEST(ReplaceConstantFunction) {
14715 LocalContext context;
14716 v8::HandleScope scope(context->GetIsolate());
14717 v8::Handle<v8::Object> obj = v8::Object::New();
14718 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New();
14719 v8::Handle<v8::String> foo_string = v8::String::New("foo");
14720 obj->Set(foo_string, func_templ->GetFunction());
14721 v8::Handle<v8::Object> obj_clone = obj->Clone();
14722 obj_clone->Set(foo_string, v8::String::New("Hello"));
14723 CHECK(!obj->Get(foo_string)->IsUndefined());
14727 // Regression test for http://crbug.com/16276.
14728 THREADED_TEST(Regress16276) {
14729 LocalContext context;
14730 v8::HandleScope scope(context->GetIsolate());
14731 // Force the IC in f to be a dictionary load IC.
14732 CompileRun("function f(obj) { return obj.x; }\n"
14733 "var obj = { x: { foo: 42 }, y: 87 };\n"
14736 "for (var i = 0; i < 5; i++) f(obj);");
14737 // Detach the global object to make 'this' refer directly to the
14738 // global object (not the proxy), and make sure that the dictionary
14739 // load IC doesn't mess up loading directly from the global object.
14740 context->DetachGlobal();
14741 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value());
14745 THREADED_TEST(PixelArray) {
14746 LocalContext context;
14747 i::Factory* factory = i::Isolate::Current()->factory();
14748 v8::HandleScope scope(context->GetIsolate());
14749 const int kElementCount = 260;
14750 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
14751 i::Handle<i::ExternalPixelArray> pixels =
14752 i::Handle<i::ExternalPixelArray>::cast(
14753 factory->NewExternalArray(kElementCount,
14754 v8::kExternalPixelArray,
14756 // Force GC to trigger verification.
14757 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14758 for (int i = 0; i < kElementCount; i++) {
14759 pixels->set(i, i % 256);
14761 // Force GC to trigger verification.
14762 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
14763 for (int i = 0; i < kElementCount; i++) {
14764 CHECK_EQ(i % 256, pixels->get_scalar(i));
14765 CHECK_EQ(i % 256, pixel_data[i]);
14768 v8::Handle<v8::Object> obj = v8::Object::New();
14769 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14770 // Set the elements to be the pixels.
14771 // jsobj->set_elements(*pixels);
14772 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
14773 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14774 obj->Set(v8_str("field"), v8::Int32::New(1503));
14775 context->Global()->Set(v8_str("pixels"), obj);
14776 v8::Handle<v8::Value> result = CompileRun("pixels.field");
14777 CHECK_EQ(1503, result->Int32Value());
14778 result = CompileRun("pixels[1]");
14779 CHECK_EQ(1, result->Int32Value());
14781 result = CompileRun("var sum = 0;"
14782 "for (var i = 0; i < 8; i++) {"
14783 " sum += pixels[i] = pixels[i] = -i;"
14786 CHECK_EQ(-28, result->Int32Value());
14788 result = CompileRun("var sum = 0;"
14789 "for (var i = 0; i < 8; i++) {"
14790 " sum += pixels[i] = pixels[i] = 0;"
14793 CHECK_EQ(0, result->Int32Value());
14795 result = CompileRun("var sum = 0;"
14796 "for (var i = 0; i < 8; i++) {"
14797 " sum += pixels[i] = pixels[i] = 255;"
14800 CHECK_EQ(8 * 255, result->Int32Value());
14802 result = CompileRun("var sum = 0;"
14803 "for (var i = 0; i < 8; i++) {"
14804 " sum += pixels[i] = pixels[i] = 256 + i;"
14807 CHECK_EQ(2076, result->Int32Value());
14809 result = CompileRun("var sum = 0;"
14810 "for (var i = 0; i < 8; i++) {"
14811 " sum += pixels[i] = pixels[i] = i;"
14814 CHECK_EQ(28, result->Int32Value());
14816 result = CompileRun("var sum = 0;"
14817 "for (var i = 0; i < 8; i++) {"
14818 " sum += pixels[i];"
14821 CHECK_EQ(28, result->Int32Value());
14823 i::Handle<i::Smi> value(i::Smi::FromInt(2),
14824 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
14825 i::Handle<i::Object> no_failure;
14827 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
14828 ASSERT(!no_failure.is_null());
14829 i::USE(no_failure);
14830 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14831 *value.location() = i::Smi::FromInt(256);
14833 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
14834 ASSERT(!no_failure.is_null());
14835 i::USE(no_failure);
14837 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14838 *value.location() = i::Smi::FromInt(-1);
14840 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode);
14841 ASSERT(!no_failure.is_null());
14842 i::USE(no_failure);
14843 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14845 result = CompileRun("for (var i = 0; i < 8; i++) {"
14846 " pixels[i] = (i * 65) - 109;"
14848 "pixels[1] + pixels[6];");
14849 CHECK_EQ(255, result->Int32Value());
14850 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
14851 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14853 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
14855 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
14857 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
14859 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
14861 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
14863 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
14864 result = CompileRun("var sum = 0;"
14865 "for (var i = 0; i < 8; i++) {"
14866 " sum += pixels[i];"
14869 CHECK_EQ(984, result->Int32Value());
14871 result = CompileRun("for (var i = 0; i < 8; i++) {"
14872 " pixels[i] = (i * 1.1);"
14874 "pixels[1] + pixels[6];");
14875 CHECK_EQ(8, result->Int32Value());
14876 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value());
14877 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value());
14878 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value());
14879 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value());
14880 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value());
14881 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
14882 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
14883 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
14885 result = CompileRun("for (var i = 0; i < 8; i++) {"
14886 " pixels[7] = undefined;"
14889 CHECK_EQ(0, result->Int32Value());
14890 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value());
14892 result = CompileRun("for (var i = 0; i < 8; i++) {"
14893 " pixels[6] = '2.3';"
14896 CHECK_EQ(2, result->Int32Value());
14897 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value());
14899 result = CompileRun("for (var i = 0; i < 8; i++) {"
14900 " pixels[5] = NaN;"
14903 CHECK_EQ(0, result->Int32Value());
14904 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
14906 result = CompileRun("for (var i = 0; i < 8; i++) {"
14907 " pixels[8] = Infinity;"
14910 CHECK_EQ(255, result->Int32Value());
14912 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value());
14914 result = CompileRun("for (var i = 0; i < 8; i++) {"
14915 " pixels[9] = -Infinity;"
14918 CHECK_EQ(0, result->Int32Value());
14919 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value());
14921 result = CompileRun("pixels[3] = 33;"
14922 "delete pixels[3];"
14924 CHECK_EQ(33, result->Int32Value());
14926 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
14927 "pixels[2] = 12; pixels[3] = 13;"
14928 "pixels.__defineGetter__('2',"
14929 "function() { return 120; });"
14931 CHECK_EQ(12, result->Int32Value());
14933 result = CompileRun("var js_array = new Array(40);"
14934 "js_array[0] = 77;"
14936 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14938 result = CompileRun("pixels[1] = 23;"
14939 "pixels.__proto__ = [];"
14940 "js_array.__proto__ = pixels;"
14941 "js_array.concat(pixels);");
14942 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14943 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
14945 result = CompileRun("pixels[1] = 23;");
14946 CHECK_EQ(23, result->Int32Value());
14948 // Test for index greater than 255. Regression test for:
14949 // http://code.google.com/p/chromium/issues/detail?id=26337.
14950 result = CompileRun("pixels[256] = 255;");
14951 CHECK_EQ(255, result->Int32Value());
14952 result = CompileRun("var i = 0;"
14953 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
14955 CHECK_EQ(255, result->Int32Value());
14957 // Make sure that pixel array ICs recognize when a non-pixel array
14958 // is passed to it.
14959 result = CompileRun("function pa_load(p) {"
14961 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
14964 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
14965 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
14966 "just_ints = new Object();"
14967 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
14968 "for (var i = 0; i < 10; ++i) {"
14969 " result = pa_load(just_ints);"
14972 CHECK_EQ(32640, result->Int32Value());
14974 // Make sure that pixel array ICs recognize out-of-bound accesses.
14975 result = CompileRun("function pa_load(p, start) {"
14977 " for (var j = start; j < 256; j++) { sum += p[j]; }"
14980 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
14981 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
14982 "for (var i = 0; i < 10; ++i) {"
14983 " result = pa_load(pixels,-10);"
14986 CHECK_EQ(0, result->Int32Value());
14988 // Make sure that generic ICs properly handles a pixel array.
14989 result = CompileRun("function pa_load(p) {"
14991 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
14994 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
14995 "just_ints = new Object();"
14996 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
14997 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
14998 "for (var i = 0; i < 10; ++i) {"
14999 " result = pa_load(pixels);"
15002 CHECK_EQ(32640, result->Int32Value());
15004 // Make sure that generic load ICs recognize out-of-bound accesses in
15006 result = CompileRun("function pa_load(p, start) {"
15008 " for (var j = start; j < 256; j++) { sum += p[j]; }"
15011 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15012 "just_ints = new Object();"
15013 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15014 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
15015 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
15016 "for (var i = 0; i < 10; ++i) {"
15017 " result = pa_load(pixels,-10);"
15020 CHECK_EQ(0, result->Int32Value());
15022 // Make sure that generic ICs properly handles other types than pixel
15023 // arrays (that the inlined fast pixel array test leaves the right information
15024 // in the right registers).
15025 result = CompileRun("function pa_load(p) {"
15027 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
15030 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15031 "just_ints = new Object();"
15032 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15033 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
15034 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
15035 "sparse_array = new Object();"
15036 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
15037 "sparse_array[1000000] = 3;"
15038 "for (var i = 0; i < 10; ++i) {"
15039 " result = pa_load(sparse_array);"
15042 CHECK_EQ(32640, result->Int32Value());
15044 // Make sure that pixel array store ICs clamp values correctly.
15045 result = CompileRun("function pa_store(p) {"
15046 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15048 "pa_store(pixels);"
15050 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15052 CHECK_EQ(48896, result->Int32Value());
15054 // Make sure that pixel array stores correctly handle accesses outside
15055 // of the pixel array..
15056 result = CompileRun("function pa_store(p,start) {"
15057 " for (var j = 0; j < 256; j++) {"
15058 " p[j+start] = j * 2;"
15061 "pa_store(pixels,0);"
15062 "pa_store(pixels,-128);"
15064 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15066 CHECK_EQ(65280, result->Int32Value());
15068 // Make sure that the generic store stub correctly handle accesses outside
15069 // of the pixel array..
15070 result = CompileRun("function pa_store(p,start) {"
15071 " for (var j = 0; j < 256; j++) {"
15072 " p[j+start] = j * 2;"
15075 "pa_store(pixels,0);"
15076 "just_ints = new Object();"
15077 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
15078 "pa_store(just_ints, 0);"
15079 "pa_store(pixels,-128);"
15081 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15083 CHECK_EQ(65280, result->Int32Value());
15085 // Make sure that the generic keyed store stub clamps pixel array values
15087 result = CompileRun("function pa_store(p) {"
15088 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
15090 "pa_store(pixels);"
15091 "just_ints = new Object();"
15092 "pa_store(just_ints);"
15093 "pa_store(pixels);"
15095 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
15097 CHECK_EQ(48896, result->Int32Value());
15099 // Make sure that pixel array loads are optimized by crankshaft.
15100 result = CompileRun("function pa_load(p) {"
15102 " for (var i=0; i<256; ++i) {"
15107 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
15108 "for (var i = 0; i < 5000; ++i) {"
15109 " result = pa_load(pixels);"
15112 CHECK_EQ(32640, result->Int32Value());
15114 // Make sure that pixel array stores are optimized by crankshaft.
15115 result = CompileRun("function pa_init(p) {"
15116 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
15118 "function pa_load(p) {"
15120 " for (var i=0; i<256; ++i) {"
15125 "for (var i = 0; i < 5000; ++i) {"
15126 " pa_init(pixels);"
15128 "result = pa_load(pixels);"
15130 CHECK_EQ(32640, result->Int32Value());
15136 THREADED_TEST(PixelArrayInfo) {
15137 LocalContext context;
15138 v8::HandleScope scope(context->GetIsolate());
15139 for (int size = 0; size < 100; size += 10) {
15140 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
15141 v8::Handle<v8::Object> obj = v8::Object::New();
15142 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
15143 CHECK(obj->HasIndexedPropertiesInPixelData());
15144 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
15145 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
15151 static void NotHandledIndexedPropertyGetter(
15153 const v8::PropertyCallbackInfo<v8::Value>& info) {
15154 ApiTestFuzzer::Fuzz();
15158 static void NotHandledIndexedPropertySetter(
15160 Local<Value> value,
15161 const v8::PropertyCallbackInfo<v8::Value>& info) {
15162 ApiTestFuzzer::Fuzz();
15166 THREADED_TEST(PixelArrayWithInterceptor) {
15167 LocalContext context;
15168 i::Factory* factory = i::Isolate::Current()->factory();
15169 v8::HandleScope scope(context->GetIsolate());
15170 const int kElementCount = 260;
15171 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
15172 i::Handle<i::ExternalPixelArray> pixels =
15173 i::Handle<i::ExternalPixelArray>::cast(
15174 factory->NewExternalArray(kElementCount,
15175 v8::kExternalPixelArray,
15177 for (int i = 0; i < kElementCount; i++) {
15178 pixels->set(i, i % 256);
15180 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New();
15181 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
15182 NotHandledIndexedPropertySetter);
15183 v8::Handle<v8::Object> obj = templ->NewInstance();
15184 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
15185 context->Global()->Set(v8_str("pixels"), obj);
15186 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
15187 CHECK_EQ(1, result->Int32Value());
15188 result = CompileRun("var sum = 0;"
15189 "for (var i = 0; i < 8; i++) {"
15190 " sum += pixels[i] = pixels[i] = -i;"
15193 CHECK_EQ(-28, result->Int32Value());
15194 result = CompileRun("pixels.hasOwnProperty('1')");
15195 CHECK(result->BooleanValue());
15200 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
15201 switch (array_type) {
15202 case v8::kExternalByteArray:
15203 case v8::kExternalUnsignedByteArray:
15204 case v8::kExternalPixelArray:
15207 case v8::kExternalShortArray:
15208 case v8::kExternalUnsignedShortArray:
15211 case v8::kExternalIntArray:
15212 case v8::kExternalUnsignedIntArray:
15213 case v8::kExternalFloatArray:
15216 case v8::kExternalDoubleArray:
15228 template <class ExternalArrayClass, class ElementType>
15229 static void ObjectWithExternalArrayTestHelper(
15230 Handle<Context> context,
15231 v8::Handle<Object> obj,
15233 v8::ExternalArrayType array_type,
15234 int64_t low, int64_t high) {
15235 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15236 obj->Set(v8_str("field"), v8::Int32::New(1503));
15237 context->Global()->Set(v8_str("ext_array"), obj);
15238 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
15239 CHECK_EQ(1503, result->Int32Value());
15240 result = CompileRun("ext_array[1]");
15241 CHECK_EQ(1, result->Int32Value());
15243 // Check pass through of assigned smis
15244 result = CompileRun("var sum = 0;"
15245 "for (var i = 0; i < 8; i++) {"
15246 " sum += ext_array[i] = ext_array[i] = -i;"
15249 CHECK_EQ(-28, result->Int32Value());
15251 // Check assigned smis
15252 result = CompileRun("for (var i = 0; i < 8; i++) {"
15253 " ext_array[i] = i;"
15256 "for (var i = 0; i < 8; i++) {"
15257 " sum += ext_array[i];"
15260 CHECK_EQ(28, result->Int32Value());
15262 // Check assigned smis in reverse order
15263 result = CompileRun("for (var i = 8; --i >= 0; ) {"
15264 " ext_array[i] = i;"
15267 "for (var i = 0; i < 8; i++) {"
15268 " sum += ext_array[i];"
15271 CHECK_EQ(28, result->Int32Value());
15273 // Check pass through of assigned HeapNumbers
15274 result = CompileRun("var sum = 0;"
15275 "for (var i = 0; i < 16; i+=2) {"
15276 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
15279 CHECK_EQ(-28, result->Int32Value());
15281 // Check assigned HeapNumbers
15282 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
15283 " ext_array[i] = (i * 0.5);"
15286 "for (var i = 0; i < 16; i+=2) {"
15287 " sum += ext_array[i];"
15290 CHECK_EQ(28, result->Int32Value());
15292 // Check assigned HeapNumbers in reverse order
15293 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
15294 " ext_array[i] = (i * 0.5);"
15297 "for (var i = 0; i < 16; i+=2) {"
15298 " sum += ext_array[i];"
15301 CHECK_EQ(28, result->Int32Value());
15303 i::ScopedVector<char> test_buf(1024);
15305 // Check legal boundary conditions.
15306 // The repeated loads and stores ensure the ICs are exercised.
15307 const char* boundary_program =
15309 "for (var i = 0; i < 16; i++) {"
15310 " ext_array[i] = %lld;"
15312 " res = ext_array[i];"
15316 i::OS::SNPrintF(test_buf,
15319 result = CompileRun(test_buf.start());
15320 CHECK_EQ(low, result->IntegerValue());
15322 i::OS::SNPrintF(test_buf,
15325 result = CompileRun(test_buf.start());
15326 CHECK_EQ(high, result->IntegerValue());
15328 // Check misprediction of type in IC.
15329 result = CompileRun("var tmp_array = ext_array;"
15331 "for (var i = 0; i < 8; i++) {"
15332 " tmp_array[i] = i;"
15333 " sum += tmp_array[i];"
15339 // Force GC to trigger verification.
15340 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15341 CHECK_EQ(28, result->Int32Value());
15343 // Make sure out-of-range loads do not throw.
15344 i::OS::SNPrintF(test_buf,
15345 "var caught_exception = false;"
15349 " caught_exception = true;"
15351 "caught_exception;",
15353 result = CompileRun(test_buf.start());
15354 CHECK_EQ(false, result->BooleanValue());
15356 // Make sure out-of-range stores do not throw.
15357 i::OS::SNPrintF(test_buf,
15358 "var caught_exception = false;"
15360 " ext_array[%d] = 1;"
15362 " caught_exception = true;"
15364 "caught_exception;",
15366 result = CompileRun(test_buf.start());
15367 CHECK_EQ(false, result->BooleanValue());
15369 // Check other boundary conditions, values and operations.
15370 result = CompileRun("for (var i = 0; i < 8; i++) {"
15371 " ext_array[7] = undefined;"
15374 CHECK_EQ(0, result->Int32Value());
15375 if (array_type == v8::kExternalDoubleArray ||
15376 array_type == v8::kExternalFloatArray) {
15378 static_cast<int>(i::OS::nan_value()),
15379 static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number()));
15381 CHECK_EQ(0, static_cast<int>(
15382 jsobj->GetElement(7)->ToObjectChecked()->Number()));
15385 result = CompileRun("for (var i = 0; i < 8; i++) {"
15386 " ext_array[6] = '2.3';"
15389 CHECK_EQ(2, result->Int32Value());
15391 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number()));
15393 if (array_type != v8::kExternalFloatArray &&
15394 array_type != v8::kExternalDoubleArray) {
15395 // Though the specification doesn't state it, be explicit about
15396 // converting NaNs and +/-Infinity to zero.
15397 result = CompileRun("for (var i = 0; i < 8; i++) {"
15398 " ext_array[i] = 5;"
15400 "for (var i = 0; i < 8; i++) {"
15401 " ext_array[i] = NaN;"
15404 CHECK_EQ(0, result->Int32Value());
15406 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
15408 result = CompileRun("for (var i = 0; i < 8; i++) {"
15409 " ext_array[i] = 5;"
15411 "for (var i = 0; i < 8; i++) {"
15412 " ext_array[i] = Infinity;"
15415 int expected_value =
15416 (array_type == v8::kExternalPixelArray) ? 255 : 0;
15417 CHECK_EQ(expected_value, result->Int32Value());
15418 CHECK_EQ(expected_value,
15419 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
15421 result = CompileRun("for (var i = 0; i < 8; i++) {"
15422 " ext_array[i] = 5;"
15424 "for (var i = 0; i < 8; i++) {"
15425 " ext_array[i] = -Infinity;"
15428 CHECK_EQ(0, result->Int32Value());
15430 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value());
15432 // Check truncation behavior of integral arrays.
15433 const char* unsigned_data =
15434 "var source_data = [0.6, 10.6];"
15435 "var expected_results = [0, 10];";
15436 const char* signed_data =
15437 "var source_data = [0.6, 10.6, -0.6, -10.6];"
15438 "var expected_results = [0, 10, 0, -10];";
15439 const char* pixel_data =
15440 "var source_data = [0.6, 10.6];"
15441 "var expected_results = [1, 11];";
15443 (array_type == v8::kExternalUnsignedByteArray ||
15444 array_type == v8::kExternalUnsignedShortArray ||
15445 array_type == v8::kExternalUnsignedIntArray);
15446 bool is_pixel_data = array_type == v8::kExternalPixelArray;
15448 i::OS::SNPrintF(test_buf,
15450 "var all_passed = true;"
15451 "for (var i = 0; i < source_data.length; i++) {"
15452 " for (var j = 0; j < 8; j++) {"
15453 " ext_array[j] = source_data[i];"
15455 " all_passed = all_passed &&"
15456 " (ext_array[5] == expected_results[i]);"
15461 (is_pixel_data ? pixel_data : signed_data)));
15462 result = CompileRun(test_buf.start());
15463 CHECK_EQ(true, result->BooleanValue());
15466 i::Handle<ExternalArrayClass> array(
15467 ExternalArrayClass::cast(jsobj->elements()));
15468 for (int i = 0; i < element_count; i++) {
15469 array->set(i, static_cast<ElementType>(i));
15472 // Test complex assignments
15473 result = CompileRun("function ee_op_test_complex_func(sum) {"
15474 " for (var i = 0; i < 40; ++i) {"
15475 " sum += (ext_array[i] += 1);"
15476 " sum += (ext_array[i] -= 1);"
15481 "for (var i=0;i<10000;++i) {"
15482 " sum=ee_op_test_complex_func(sum);"
15485 CHECK_EQ(16000000, result->Int32Value());
15487 // Test count operations
15488 result = CompileRun("function ee_op_test_count_func(sum) {"
15489 " for (var i = 0; i < 40; ++i) {"
15490 " sum += (++ext_array[i]);"
15491 " sum += (--ext_array[i]);"
15496 "for (var i=0;i<10000;++i) {"
15497 " sum=ee_op_test_count_func(sum);"
15500 CHECK_EQ(16000000, result->Int32Value());
15502 result = CompileRun("ext_array[3] = 33;"
15503 "delete ext_array[3];"
15505 CHECK_EQ(33, result->Int32Value());
15507 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
15508 "ext_array[2] = 12; ext_array[3] = 13;"
15509 "ext_array.__defineGetter__('2',"
15510 "function() { return 120; });"
15512 CHECK_EQ(12, result->Int32Value());
15514 result = CompileRun("var js_array = new Array(40);"
15515 "js_array[0] = 77;"
15517 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15519 result = CompileRun("ext_array[1] = 23;"
15520 "ext_array.__proto__ = [];"
15521 "js_array.__proto__ = ext_array;"
15522 "js_array.concat(ext_array);");
15523 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
15524 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
15526 result = CompileRun("ext_array[1] = 23;");
15527 CHECK_EQ(23, result->Int32Value());
15531 template <class ExternalArrayClass, class ElementType>
15532 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
15535 LocalContext context;
15536 i::Factory* factory = i::Isolate::Current()->factory();
15537 v8::HandleScope scope(context->GetIsolate());
15538 const int kElementCount = 40;
15539 int element_size = ExternalArrayElementSize(array_type);
15540 ElementType* array_data =
15541 static_cast<ElementType*>(malloc(kElementCount * element_size));
15542 i::Handle<ExternalArrayClass> array =
15543 i::Handle<ExternalArrayClass>::cast(
15544 factory->NewExternalArray(kElementCount, array_type, array_data));
15545 // Force GC to trigger verification.
15546 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15547 for (int i = 0; i < kElementCount; i++) {
15548 array->set(i, static_cast<ElementType>(i));
15550 // Force GC to trigger verification.
15551 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
15552 for (int i = 0; i < kElementCount; i++) {
15553 CHECK_EQ(static_cast<int64_t>(i),
15554 static_cast<int64_t>(array->get_scalar(i)));
15555 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
15558 v8::Handle<v8::Object> obj = v8::Object::New();
15559 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
15560 // Set the elements to be the external array.
15561 obj->SetIndexedPropertiesToExternalArrayData(array_data,
15565 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number()));
15567 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
15568 context.local(), obj, kElementCount, array_type, low, high);
15570 v8::Handle<v8::Value> result;
15572 // Test more complex manipulations which cause eax to contain values
15573 // that won't be completely overwritten by loads from the arrays.
15574 // This catches bugs in the instructions used for the KeyedLoadIC
15575 // for byte and word types.
15577 const int kXSize = 300;
15578 const int kYSize = 300;
15579 const int kLargeElementCount = kXSize * kYSize * 4;
15580 ElementType* large_array_data =
15581 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
15582 v8::Handle<v8::Object> large_obj = v8::Object::New();
15583 // Set the elements to be the external array.
15584 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
15586 kLargeElementCount);
15587 context->Global()->Set(v8_str("large_array"), large_obj);
15588 // Initialize contents of a few rows.
15589 for (int x = 0; x < 300; x++) {
15591 int offset = row * 300 * 4;
15592 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
15593 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
15594 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
15595 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
15597 offset = row * 300 * 4;
15598 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
15599 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
15600 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
15601 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
15603 offset = row * 300 * 4;
15604 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
15605 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
15606 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
15607 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
15609 // The goal of the code below is to make "offset" large enough
15610 // that the computation of the index (which goes into eax) has
15611 // high bits set which will not be overwritten by a byte or short
15613 result = CompileRun("var failed = false;"
15615 "for (var i = 0; i < 300; i++) {"
15616 " if (large_array[4 * i] != 127 ||"
15617 " large_array[4 * i + 1] != 0 ||"
15618 " large_array[4 * i + 2] != 0 ||"
15619 " large_array[4 * i + 3] != 127) {"
15623 "offset = 150 * 300 * 4;"
15624 "for (var i = 0; i < 300; i++) {"
15625 " if (large_array[offset + 4 * i] != 127 ||"
15626 " large_array[offset + 4 * i + 1] != 0 ||"
15627 " large_array[offset + 4 * i + 2] != 0 ||"
15628 " large_array[offset + 4 * i + 3] != 127) {"
15632 "offset = 298 * 300 * 4;"
15633 "for (var i = 0; i < 300; i++) {"
15634 " if (large_array[offset + 4 * i] != 127 ||"
15635 " large_array[offset + 4 * i + 1] != 0 ||"
15636 " large_array[offset + 4 * i + 2] != 0 ||"
15637 " large_array[offset + 4 * i + 3] != 127) {"
15642 CHECK_EQ(true, result->BooleanValue());
15643 free(large_array_data);
15646 // The "" property descriptor is overloaded to store information about
15647 // the external array. Ensure that setting and accessing the "" property
15648 // works (it should overwrite the information cached about the external
15649 // array in the DescriptorArray) in various situations.
15650 result = CompileRun("ext_array[''] = 23; ext_array['']");
15651 CHECK_EQ(23, result->Int32Value());
15653 // Property "" set after the external array is associated with the object.
15655 v8::Handle<v8::Object> obj2 = v8::Object::New();
15656 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256));
15657 obj2->Set(v8_str(""), v8::Int32::New(1503));
15658 // Set the elements to be the external array.
15659 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
15662 context->Global()->Set(v8_str("ext_array"), obj2);
15663 result = CompileRun("ext_array['']");
15664 CHECK_EQ(1503, result->Int32Value());
15667 // Property "" set after the external array is associated with the object.
15669 v8::Handle<v8::Object> obj2 = v8::Object::New();
15670 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
15671 // Set the elements to be the external array.
15672 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
15675 obj2->Set(v8_str(""), v8::Int32::New(1503));
15676 context->Global()->Set(v8_str("ext_array"), obj2);
15677 result = CompileRun("ext_array['']");
15678 CHECK_EQ(1503, result->Int32Value());
15681 // Should reuse the map from previous test.
15683 v8::Handle<v8::Object> obj2 = v8::Object::New();
15684 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256));
15685 // Set the elements to be the external array. Should re-use the map
15686 // from previous test.
15687 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
15690 context->Global()->Set(v8_str("ext_array"), obj2);
15691 result = CompileRun("ext_array['']");
15694 // Property "" is a constant function that shouldn't not be interfered with
15695 // when an external array is set.
15697 v8::Handle<v8::Object> obj2 = v8::Object::New();
15699 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
15701 // Add a constant function to an object.
15702 context->Global()->Set(v8_str("ext_array"), obj2);
15703 result = CompileRun("ext_array[''] = function() {return 1503;};"
15704 "ext_array['']();");
15706 // Add an external array transition to the same map that
15707 // has the constant transition.
15708 v8::Handle<v8::Object> obj3 = v8::Object::New();
15709 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256));
15710 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
15713 context->Global()->Set(v8_str("ext_array"), obj3);
15716 // If a external array transition is in the map, it should get clobbered
15717 // by a constant function.
15719 // Add an external array transition.
15720 v8::Handle<v8::Object> obj3 = v8::Object::New();
15721 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
15722 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
15726 // Add a constant function to the same map that just got an external array
15728 v8::Handle<v8::Object> obj2 = v8::Object::New();
15729 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256));
15730 context->Global()->Set(v8_str("ext_array"), obj2);
15731 result = CompileRun("ext_array[''] = function() {return 1503;};"
15732 "ext_array['']();");
15739 THREADED_TEST(ExternalByteArray) {
15740 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>(
15741 v8::kExternalByteArray,
15747 THREADED_TEST(ExternalUnsignedByteArray) {
15748 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>(
15749 v8::kExternalUnsignedByteArray,
15755 THREADED_TEST(ExternalPixelArray) {
15756 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>(
15757 v8::kExternalPixelArray,
15763 THREADED_TEST(ExternalShortArray) {
15764 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>(
15765 v8::kExternalShortArray,
15771 THREADED_TEST(ExternalUnsignedShortArray) {
15772 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>(
15773 v8::kExternalUnsignedShortArray,
15779 THREADED_TEST(ExternalIntArray) {
15780 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>(
15781 v8::kExternalIntArray,
15782 INT_MIN, // -2147483648
15783 INT_MAX); // 2147483647
15787 THREADED_TEST(ExternalUnsignedIntArray) {
15788 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>(
15789 v8::kExternalUnsignedIntArray,
15791 UINT_MAX); // 4294967295
15795 THREADED_TEST(ExternalFloatArray) {
15796 ExternalArrayTestHelper<i::ExternalFloatArray, float>(
15797 v8::kExternalFloatArray,
15803 THREADED_TEST(ExternalDoubleArray) {
15804 ExternalArrayTestHelper<i::ExternalDoubleArray, double>(
15805 v8::kExternalDoubleArray,
15811 THREADED_TEST(ExternalArrays) {
15812 TestExternalByteArray();
15813 TestExternalUnsignedByteArray();
15814 TestExternalShortArray();
15815 TestExternalUnsignedShortArray();
15816 TestExternalIntArray();
15817 TestExternalUnsignedIntArray();
15818 TestExternalFloatArray();
15822 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
15823 LocalContext context;
15824 v8::HandleScope scope(context->GetIsolate());
15825 for (int size = 0; size < 100; size += 10) {
15826 int element_size = ExternalArrayElementSize(array_type);
15827 void* external_data = malloc(size * element_size);
15828 v8::Handle<v8::Object> obj = v8::Object::New();
15829 obj->SetIndexedPropertiesToExternalArrayData(
15830 external_data, array_type, size);
15831 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
15832 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
15833 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
15834 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
15835 free(external_data);
15840 THREADED_TEST(ExternalArrayInfo) {
15841 ExternalArrayInfoTestHelper(v8::kExternalByteArray);
15842 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray);
15843 ExternalArrayInfoTestHelper(v8::kExternalShortArray);
15844 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray);
15845 ExternalArrayInfoTestHelper(v8::kExternalIntArray);
15846 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray);
15847 ExternalArrayInfoTestHelper(v8::kExternalFloatArray);
15848 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray);
15849 ExternalArrayInfoTestHelper(v8::kExternalPixelArray);
15853 void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) {
15854 v8::Handle<v8::Object> obj = v8::Object::New();
15855 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
15856 last_location = last_message = NULL;
15857 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
15858 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
15859 CHECK_NE(NULL, last_location);
15860 CHECK_NE(NULL, last_message);
15864 TEST(ExternalArrayLimits) {
15865 LocalContext context;
15866 v8::HandleScope scope(context->GetIsolate());
15867 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000);
15868 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff);
15869 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000);
15870 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff);
15871 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000);
15872 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff);
15873 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000);
15874 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff);
15875 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000);
15876 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff);
15877 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000);
15878 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff);
15879 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000);
15880 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff);
15881 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000);
15882 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff);
15883 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000);
15884 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff);
15888 template <typename ElementType, typename TypedArray,
15889 class ExternalArrayClass>
15890 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
15891 int64_t low, int64_t high) {
15892 const int kElementCount = 50;
15894 i::ScopedVector<ElementType> backing_store(kElementCount+2);
15897 v8::Isolate* isolate = env->GetIsolate();
15898 v8::HandleScope handle_scope(isolate);
15900 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
15901 backing_store.start(), (kElementCount+2)*sizeof(ElementType));
15902 Local<TypedArray> ta =
15903 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
15904 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
15905 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
15906 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
15907 CHECK_EQ(kElementCount*sizeof(ElementType),
15908 static_cast<int>(ta->ByteLength()));
15909 CHECK_EQ(ab, ta->Buffer());
15911 ElementType* data = backing_store.start() + 2;
15912 for (int i = 0; i < kElementCount; i++) {
15913 data[i] = static_cast<ElementType>(i);
15916 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
15917 env.local(), ta, kElementCount, array_type, low, high);
15921 THREADED_TEST(Uint8Array) {
15922 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUnsignedByteArray>(
15923 v8::kExternalUnsignedByteArray, 0, 0xFF);
15927 THREADED_TEST(Int8Array) {
15928 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalByteArray>(
15929 v8::kExternalByteArray, -0x80, 0x7F);
15933 THREADED_TEST(Uint16Array) {
15934 TypedArrayTestHelper<uint16_t,
15936 i::ExternalUnsignedShortArray>(
15937 v8::kExternalUnsignedShortArray, 0, 0xFFFF);
15941 THREADED_TEST(Int16Array) {
15942 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalShortArray>(
15943 v8::kExternalShortArray, -0x8000, 0x7FFF);
15947 THREADED_TEST(Uint32Array) {
15948 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUnsignedIntArray>(
15949 v8::kExternalUnsignedIntArray, 0, UINT_MAX);
15953 THREADED_TEST(Int32Array) {
15954 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalIntArray>(
15955 v8::kExternalIntArray, INT_MIN, INT_MAX);
15959 THREADED_TEST(Float32Array) {
15960 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloatArray>(
15961 v8::kExternalFloatArray, -500, 500);
15965 THREADED_TEST(Float64Array) {
15966 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalDoubleArray>(
15967 v8::kExternalDoubleArray, -500, 500);
15971 THREADED_TEST(Uint8ClampedArray) {
15972 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, i::ExternalPixelArray>(
15973 v8::kExternalPixelArray, 0, 0xFF);
15977 THREADED_TEST(DataView) {
15978 const int kSize = 50;
15980 i::ScopedVector<uint8_t> backing_store(kSize+2);
15983 v8::Isolate* isolate = env->GetIsolate();
15984 v8::HandleScope handle_scope(isolate);
15986 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
15987 backing_store.start(), 2 + kSize);
15988 Local<v8::DataView> dv =
15989 v8::DataView::New(ab, 2, kSize);
15990 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
15991 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
15992 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
15993 CHECK_EQ(ab, dv->Buffer());
15997 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
15998 THREADED_TEST(Is##View) { \
15999 i::FLAG_harmony_array_buffer = true; \
16000 i::FLAG_harmony_typed_arrays = true; \
16001 LocalContext env; \
16002 v8::Isolate* isolate = env->GetIsolate(); \
16003 v8::HandleScope handle_scope(isolate); \
16005 Handle<Value> result = CompileRun( \
16006 "var ab = new ArrayBuffer(128);" \
16007 "new " #View "(ab)"); \
16008 CHECK(result->IsArrayBufferView()); \
16009 CHECK(result->Is##View()); \
16010 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
16013 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
16014 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
16015 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
16016 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
16017 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
16018 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
16019 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
16020 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
16021 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
16022 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
16024 #undef IS_ARRAY_BUFFER_VIEW_TEST
16028 THREADED_TEST(ScriptContextDependence) {
16030 v8::HandleScope scope(c1->GetIsolate());
16031 const char *source = "foo";
16032 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source));
16033 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source));
16034 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100));
16035 CHECK_EQ(dep->Run()->Int32Value(), 100);
16036 CHECK_EQ(indep->Run()->Int32Value(), 100);
16038 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101));
16039 CHECK_EQ(dep->Run()->Int32Value(), 100);
16040 CHECK_EQ(indep->Run()->Int32Value(), 101);
16044 THREADED_TEST(StackTrace) {
16045 LocalContext context;
16046 v8::HandleScope scope(context->GetIsolate());
16047 v8::TryCatch try_catch;
16048 const char *source = "function foo() { FAIL.FAIL; }; foo();";
16049 v8::Handle<v8::String> src = v8::String::New(source);
16050 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test");
16051 v8::Script::New(src, origin)->Run();
16052 CHECK(try_catch.HasCaught());
16053 v8::String::Utf8Value stack(try_catch.StackTrace());
16054 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
16058 // Checks that a StackFrame has certain expected values.
16059 void checkStackFrame(const char* expected_script_name,
16060 const char* expected_func_name, int expected_line_number,
16061 int expected_column, bool is_eval, bool is_constructor,
16062 v8::Handle<v8::StackFrame> frame) {
16063 v8::HandleScope scope(v8::Isolate::GetCurrent());
16064 v8::String::Utf8Value func_name(frame->GetFunctionName());
16065 v8::String::Utf8Value script_name(frame->GetScriptName());
16066 if (*script_name == NULL) {
16067 // The situation where there is no associated script, like for evals.
16068 CHECK(expected_script_name == NULL);
16070 CHECK(strstr(*script_name, expected_script_name) != NULL);
16072 CHECK(strstr(*func_name, expected_func_name) != NULL);
16073 CHECK_EQ(expected_line_number, frame->GetLineNumber());
16074 CHECK_EQ(expected_column, frame->GetColumn());
16075 CHECK_EQ(is_eval, frame->IsEval());
16076 CHECK_EQ(is_constructor, frame->IsConstructor());
16080 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
16081 v8::HandleScope scope(args.GetIsolate());
16082 const char* origin = "capture-stack-trace-test";
16083 const int kOverviewTest = 1;
16084 const int kDetailedTest = 2;
16086 ASSERT(args.Length() == 1);
16088 int testGroup = args[0]->Int32Value();
16089 if (testGroup == kOverviewTest) {
16090 v8::Handle<v8::StackTrace> stackTrace =
16091 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
16092 CHECK_EQ(4, stackTrace->GetFrameCount());
16093 checkStackFrame(origin, "bar", 2, 10, false, false,
16094 stackTrace->GetFrame(0));
16095 checkStackFrame(origin, "foo", 6, 3, false, false,
16096 stackTrace->GetFrame(1));
16097 // This is the source string inside the eval which has the call to foo.
16098 checkStackFrame(NULL, "", 1, 5, false, false,
16099 stackTrace->GetFrame(2));
16100 // The last frame is an anonymous function which has the initial eval call.
16101 checkStackFrame(origin, "", 8, 7, false, false,
16102 stackTrace->GetFrame(3));
16104 CHECK(stackTrace->AsArray()->IsArray());
16105 } else if (testGroup == kDetailedTest) {
16106 v8::Handle<v8::StackTrace> stackTrace =
16107 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16108 CHECK_EQ(4, stackTrace->GetFrameCount());
16109 checkStackFrame(origin, "bat", 4, 22, false, false,
16110 stackTrace->GetFrame(0));
16111 checkStackFrame(origin, "baz", 8, 3, false, true,
16112 stackTrace->GetFrame(1));
16113 #ifdef ENABLE_DEBUGGER_SUPPORT
16114 bool is_eval = true;
16115 #else // ENABLE_DEBUGGER_SUPPORT
16116 bool is_eval = false;
16117 #endif // ENABLE_DEBUGGER_SUPPORT
16119 // This is the source string inside the eval which has the call to baz.
16120 checkStackFrame(NULL, "", 1, 5, is_eval, false,
16121 stackTrace->GetFrame(2));
16122 // The last frame is an anonymous function which has the initial eval call.
16123 checkStackFrame(origin, "", 10, 1, false, false,
16124 stackTrace->GetFrame(3));
16126 CHECK(stackTrace->AsArray()->IsArray());
16131 // Tests the C++ StackTrace API.
16132 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
16133 // THREADED_TEST(CaptureStackTrace) {
16134 TEST(CaptureStackTrace) {
16135 v8::HandleScope scope(v8::Isolate::GetCurrent());
16136 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
16137 Local<ObjectTemplate> templ = ObjectTemplate::New();
16138 templ->Set(v8_str("AnalyzeStackInNativeCode"),
16139 v8::FunctionTemplate::New(AnalyzeStackInNativeCode));
16140 LocalContext context(0, templ);
16142 // Test getting OVERVIEW information. Should ignore information that is not
16143 // script name, function name, line number, and column offset.
16144 const char *overview_source =
16145 "function bar() {\n"
16146 " var y; AnalyzeStackInNativeCode(1);\n"
16148 "function foo() {\n"
16152 "var x;eval('new foo();');";
16153 v8::Handle<v8::String> overview_src = v8::String::New(overview_source);
16154 v8::Handle<Value> overview_result(
16155 v8::Script::New(overview_src, origin)->Run());
16156 CHECK(!overview_result.IsEmpty());
16157 CHECK(overview_result->IsObject());
16159 // Test getting DETAILED information.
16160 const char *detailed_source =
16161 "function bat() {AnalyzeStackInNativeCode(2);\n"
16164 "function baz() {\n"
16167 "eval('new baz();');";
16168 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source);
16169 // Make the script using a non-zero line and column offset.
16170 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3);
16171 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5);
16172 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
16173 v8::Handle<v8::Script> detailed_script(
16174 v8::Script::New(detailed_src, &detailed_origin));
16175 v8::Handle<Value> detailed_result(detailed_script->Run());
16176 CHECK(!detailed_result.IsEmpty());
16177 CHECK(detailed_result->IsObject());
16181 static void StackTraceForUncaughtExceptionListener(
16182 v8::Handle<v8::Message> message,
16183 v8::Handle<Value>) {
16184 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16185 CHECK_EQ(2, stack_trace->GetFrameCount());
16186 checkStackFrame("origin", "foo", 2, 3, false, false,
16187 stack_trace->GetFrame(0));
16188 checkStackFrame("origin", "bar", 5, 3, false, false,
16189 stack_trace->GetFrame(1));
16193 TEST(CaptureStackTraceForUncaughtException) {
16196 v8::HandleScope scope(env->GetIsolate());
16197 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
16198 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16200 Script::Compile(v8_str("function foo() {\n"
16203 "function bar() {\n"
16206 v8_str("origin"))->Run();
16207 v8::Local<v8::Object> global = env->Global();
16208 Local<Value> trouble = global->Get(v8_str("bar"));
16209 CHECK(trouble->IsFunction());
16210 Function::Cast(*trouble)->Call(global, 0, NULL);
16211 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16212 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
16216 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
16218 v8::HandleScope scope(env->GetIsolate());
16219 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
16221 v8::StackTrace::kDetailed);
16224 "var setters = ['column', 'lineNumber', 'scriptName',\n"
16225 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
16226 " 'isConstructor'];\n"
16227 "for (var i = 0; i < setters.length; i++) {\n"
16228 " var prop = setters[i];\n"
16229 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
16231 CompileRun("throw 'exception';");
16232 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16236 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
16237 v8::Handle<v8::Value> data) {
16238 // Use the frame where JavaScript is called from.
16239 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16240 CHECK(!stack_trace.IsEmpty());
16241 int frame_count = stack_trace->GetFrameCount();
16242 CHECK_EQ(3, frame_count);
16243 int line_number[] = {1, 2, 5};
16244 for (int i = 0; i < frame_count; i++) {
16245 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
16250 // Test that we only return the stack trace at the site where the exception
16251 // is first thrown (not where it is rethrown).
16252 TEST(RethrowStackTrace) {
16254 v8::HandleScope scope(env->GetIsolate());
16255 // We make sure that
16256 // - the stack trace of the ReferenceError in g() is reported.
16257 // - the stack trace is not overwritten when e1 is rethrown by t().
16258 // - the stack trace of e2 does not overwrite that of e1.
16259 const char* source =
16260 "function g() { error; } \n"
16261 "function f() { g(); } \n"
16262 "function t(e) { throw e; } \n"
16265 "} catch (e1) { \n"
16268 " } catch (e2) { \n"
16272 v8::V8::AddMessageListener(RethrowStackTraceHandler);
16273 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16274 CompileRun(source);
16275 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16276 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
16280 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
16281 v8::Handle<v8::Value> data) {
16282 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16283 CHECK(!stack_trace.IsEmpty());
16284 int frame_count = stack_trace->GetFrameCount();
16285 CHECK_EQ(2, frame_count);
16286 int line_number[] = {3, 7};
16287 for (int i = 0; i < frame_count; i++) {
16288 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
16293 // Test that we do not recognize identity for primitive exceptions.
16294 TEST(RethrowPrimitiveStackTrace) {
16296 v8::HandleScope scope(env->GetIsolate());
16297 // We do not capture stack trace for non Error objects on creation time.
16298 // Instead, we capture the stack trace on last throw.
16299 const char* source =
16300 "function g() { throw 404; } \n"
16301 "function f() { g(); } \n"
16302 "function t(e) { throw e; } \n"
16305 "} catch (e1) { \n"
16308 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
16309 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16310 CompileRun(source);
16311 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16312 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
16316 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
16317 v8::Handle<v8::Value> data) {
16318 // Use the frame where JavaScript is called from.
16319 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16320 CHECK(!stack_trace.IsEmpty());
16321 CHECK_EQ(1, stack_trace->GetFrameCount());
16322 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
16326 // Test that the stack trace is captured when the error object is created and
16327 // not where it is thrown.
16328 TEST(RethrowExistingStackTrace) {
16330 v8::HandleScope scope(env->GetIsolate());
16331 const char* source =
16332 "var e = new Error(); \n"
16334 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
16335 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16336 CompileRun(source);
16337 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16338 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
16342 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
16343 v8::Handle<v8::Value> data) {
16344 // Use the frame where JavaScript is called from.
16345 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
16346 CHECK(!stack_trace.IsEmpty());
16347 CHECK_EQ(1, stack_trace->GetFrameCount());
16348 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
16352 // Test that the stack trace is captured where the bogus Error object is thrown.
16353 TEST(RethrowBogusErrorStackTrace) {
16355 v8::HandleScope scope(env->GetIsolate());
16356 const char* source =
16357 "var e = {__proto__: new Error()} \n"
16359 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
16360 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
16361 CompileRun(source);
16362 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
16363 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
16367 void AnalyzeStackOfEvalWithSourceURL(
16368 const v8::FunctionCallbackInfo<v8::Value>& args) {
16369 v8::HandleScope scope(args.GetIsolate());
16370 v8::Handle<v8::StackTrace> stackTrace =
16371 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16372 CHECK_EQ(5, stackTrace->GetFrameCount());
16373 v8::Handle<v8::String> url = v8_str("eval_url");
16374 for (int i = 0; i < 3; i++) {
16375 v8::Handle<v8::String> name =
16376 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16377 CHECK(!name.IsEmpty());
16378 CHECK_EQ(url, name);
16383 TEST(SourceURLInStackTrace) {
16384 v8::HandleScope scope(v8::Isolate::GetCurrent());
16385 Local<ObjectTemplate> templ = ObjectTemplate::New();
16386 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
16387 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL));
16388 LocalContext context(0, templ);
16390 const char *source =
16391 "function outer() {\n"
16392 "function bar() {\n"
16393 " AnalyzeStackOfEvalWithSourceURL();\n"
16395 "function foo() {\n"
16401 "eval('(' + outer +')()%s');";
16403 i::ScopedVector<char> code(1024);
16404 i::OS::SNPrintF(code, source, "//# sourceURL=eval_url");
16405 CHECK(CompileRun(code.start())->IsUndefined());
16406 i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url");
16407 CHECK(CompileRun(code.start())->IsUndefined());
16411 void AnalyzeStackOfInlineScriptWithSourceURL(
16412 const v8::FunctionCallbackInfo<v8::Value>& args) {
16413 v8::HandleScope scope(args.GetIsolate());
16414 v8::Handle<v8::StackTrace> stackTrace =
16415 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16416 CHECK_EQ(4, stackTrace->GetFrameCount());
16417 v8::Handle<v8::String> url = v8_str("url");
16418 for (int i = 0; i < 3; i++) {
16419 v8::Handle<v8::String> name =
16420 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16421 CHECK(!name.IsEmpty());
16422 CHECK_EQ(url, name);
16427 TEST(InlineScriptWithSourceURLInStackTrace) {
16428 v8::HandleScope scope(v8::Isolate::GetCurrent());
16429 Local<ObjectTemplate> templ = ObjectTemplate::New();
16430 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
16431 v8::FunctionTemplate::New(
16432 AnalyzeStackOfInlineScriptWithSourceURL));
16433 LocalContext context(0, templ);
16435 const char *source =
16436 "function outer() {\n"
16437 "function bar() {\n"
16438 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
16440 "function foo() {\n"
16448 i::ScopedVector<char> code(1024);
16449 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
16450 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
16451 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
16452 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
16456 void AnalyzeStackOfDynamicScriptWithSourceURL(
16457 const v8::FunctionCallbackInfo<v8::Value>& args) {
16458 v8::HandleScope scope(args.GetIsolate());
16459 v8::Handle<v8::StackTrace> stackTrace =
16460 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
16461 CHECK_EQ(4, stackTrace->GetFrameCount());
16462 v8::Handle<v8::String> url = v8_str("source_url");
16463 for (int i = 0; i < 3; i++) {
16464 v8::Handle<v8::String> name =
16465 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
16466 CHECK(!name.IsEmpty());
16467 CHECK_EQ(url, name);
16472 TEST(DynamicWithSourceURLInStackTrace) {
16473 v8::HandleScope scope(v8::Isolate::GetCurrent());
16474 Local<ObjectTemplate> templ = ObjectTemplate::New();
16475 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
16476 v8::FunctionTemplate::New(
16477 AnalyzeStackOfDynamicScriptWithSourceURL));
16478 LocalContext context(0, templ);
16480 const char *source =
16481 "function outer() {\n"
16482 "function bar() {\n"
16483 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
16485 "function foo() {\n"
16493 i::ScopedVector<char> code(1024);
16494 i::OS::SNPrintF(code, source, "//# sourceURL=source_url");
16495 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
16496 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url");
16497 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
16501 static void CreateGarbageInOldSpace() {
16502 i::Factory* factory = i::Isolate::Current()->factory();
16503 v8::HandleScope scope(v8::Isolate::GetCurrent());
16504 i::AlwaysAllocateScope always_allocate;
16505 for (int i = 0; i < 1000; i++) {
16506 factory->NewFixedArray(1000, i::TENURED);
16511 // Test that idle notification can be handled and eventually returns true.
16512 TEST(IdleNotification) {
16513 const intptr_t MB = 1024 * 1024;
16515 v8::HandleScope scope(env->GetIsolate());
16516 intptr_t initial_size = HEAP->SizeOfObjects();
16517 CreateGarbageInOldSpace();
16518 intptr_t size_with_garbage = HEAP->SizeOfObjects();
16519 CHECK_GT(size_with_garbage, initial_size + MB);
16520 bool finished = false;
16521 for (int i = 0; i < 200 && !finished; i++) {
16522 finished = v8::V8::IdleNotification();
16524 intptr_t final_size = HEAP->SizeOfObjects();
16526 CHECK_LT(final_size, initial_size + 1);
16530 // Test that idle notification can be handled and eventually collects garbage.
16531 TEST(IdleNotificationWithSmallHint) {
16532 const intptr_t MB = 1024 * 1024;
16533 const int IdlePauseInMs = 900;
16535 v8::HandleScope scope(env->GetIsolate());
16536 intptr_t initial_size = HEAP->SizeOfObjects();
16537 CreateGarbageInOldSpace();
16538 intptr_t size_with_garbage = HEAP->SizeOfObjects();
16539 CHECK_GT(size_with_garbage, initial_size + MB);
16540 bool finished = false;
16541 for (int i = 0; i < 200 && !finished; i++) {
16542 finished = v8::V8::IdleNotification(IdlePauseInMs);
16544 intptr_t final_size = HEAP->SizeOfObjects();
16546 CHECK_LT(final_size, initial_size + 1);
16550 // Test that idle notification can be handled and eventually collects garbage.
16551 TEST(IdleNotificationWithLargeHint) {
16552 const intptr_t MB = 1024 * 1024;
16553 const int IdlePauseInMs = 900;
16555 v8::HandleScope scope(env->GetIsolate());
16556 intptr_t initial_size = HEAP->SizeOfObjects();
16557 CreateGarbageInOldSpace();
16558 intptr_t size_with_garbage = HEAP->SizeOfObjects();
16559 CHECK_GT(size_with_garbage, initial_size + MB);
16560 bool finished = false;
16561 for (int i = 0; i < 200 && !finished; i++) {
16562 finished = v8::V8::IdleNotification(IdlePauseInMs);
16564 intptr_t final_size = HEAP->SizeOfObjects();
16566 CHECK_LT(final_size, initial_size + 1);
16570 TEST(Regress2107) {
16571 const intptr_t MB = 1024 * 1024;
16572 const int kShortIdlePauseInMs = 100;
16573 const int kLongIdlePauseInMs = 1000;
16575 v8::Isolate* isolate = env->GetIsolate();
16576 v8::HandleScope scope(env->GetIsolate());
16577 intptr_t initial_size = HEAP->SizeOfObjects();
16578 // Send idle notification to start a round of incremental GCs.
16579 v8::V8::IdleNotification(kShortIdlePauseInMs);
16580 // Emulate 7 page reloads.
16581 for (int i = 0; i < 7; i++) {
16583 v8::HandleScope inner_scope(env->GetIsolate());
16584 v8::Local<v8::Context> ctx = v8::Context::New(isolate);
16586 CreateGarbageInOldSpace();
16589 v8::V8::ContextDisposedNotification();
16590 v8::V8::IdleNotification(kLongIdlePauseInMs);
16592 // Create garbage and check that idle notification still collects it.
16593 CreateGarbageInOldSpace();
16594 intptr_t size_with_garbage = HEAP->SizeOfObjects();
16595 CHECK_GT(size_with_garbage, initial_size + MB);
16596 bool finished = false;
16597 for (int i = 0; i < 200 && !finished; i++) {
16598 finished = v8::V8::IdleNotification(kShortIdlePauseInMs);
16600 intptr_t final_size = HEAP->SizeOfObjects();
16601 CHECK_LT(final_size, initial_size + 1);
16604 static uint32_t* stack_limit;
16606 static void GetStackLimitCallback(
16607 const v8::FunctionCallbackInfo<v8::Value>& args) {
16608 stack_limit = reinterpret_cast<uint32_t*>(
16609 i::Isolate::Current()->stack_guard()->real_climit());
16613 // Uses the address of a local variable to determine the stack top now.
16614 // Given a size, returns an address that is that far from the current
16616 static uint32_t* ComputeStackLimit(uint32_t size) {
16617 uint32_t* answer = &size - (size / sizeof(size));
16618 // If the size is very large and the stack is very near the bottom of
16619 // memory then the calculation above may wrap around and give an address
16620 // that is above the (downwards-growing) stack. In that case we return
16621 // a very low address.
16622 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
16627 // We need at least 165kB for an x64 debug build with clang and ASAN.
16628 static const int stack_breathing_room = 256 * i::KB;
16631 TEST(SetResourceConstraints) {
16632 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
16634 // Set stack limit.
16635 v8::ResourceConstraints constraints;
16636 constraints.set_stack_limit(set_limit);
16637 CHECK(v8::SetResourceConstraints(&constraints));
16639 // Execute a script.
16641 v8::HandleScope scope(env->GetIsolate());
16642 Local<v8::FunctionTemplate> fun_templ =
16643 v8::FunctionTemplate::New(GetStackLimitCallback);
16644 Local<Function> fun = fun_templ->GetFunction();
16645 env->Global()->Set(v8_str("get_stack_limit"), fun);
16646 CompileRun("get_stack_limit();");
16648 CHECK(stack_limit == set_limit);
16652 TEST(SetResourceConstraintsInThread) {
16653 uint32_t* set_limit;
16655 v8::Locker locker(CcTest::default_isolate());
16656 set_limit = ComputeStackLimit(stack_breathing_room);
16658 // Set stack limit.
16659 v8::ResourceConstraints constraints;
16660 constraints.set_stack_limit(set_limit);
16661 CHECK(v8::SetResourceConstraints(&constraints));
16663 // Execute a script.
16664 v8::HandleScope scope(CcTest::default_isolate());
16666 Local<v8::FunctionTemplate> fun_templ =
16667 v8::FunctionTemplate::New(GetStackLimitCallback);
16668 Local<Function> fun = fun_templ->GetFunction();
16669 env->Global()->Set(v8_str("get_stack_limit"), fun);
16670 CompileRun("get_stack_limit();");
16672 CHECK(stack_limit == set_limit);
16675 v8::Locker locker(CcTest::default_isolate());
16676 CHECK(stack_limit == set_limit);
16681 THREADED_TEST(GetHeapStatistics) {
16683 v8::HandleScope scope(c1->GetIsolate());
16684 v8::HeapStatistics heap_statistics;
16685 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
16686 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
16687 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
16688 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
16689 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
16693 class VisitorImpl : public v8::ExternalResourceVisitor {
16695 explicit VisitorImpl(TestResource** resource) {
16696 for (int i = 0; i < 4; i++) {
16697 resource_[i] = resource[i];
16698 found_resource_[i] = false;
16701 virtual ~VisitorImpl() {}
16702 virtual void VisitExternalString(v8::Handle<v8::String> string) {
16703 if (!string->IsExternal()) {
16704 CHECK(string->IsExternalAscii());
16707 v8::String::ExternalStringResource* resource =
16708 string->GetExternalStringResource();
16710 for (int i = 0; i < 4; i++) {
16711 if (resource_[i] == resource) {
16712 CHECK(!found_resource_[i]);
16713 found_resource_[i] = true;
16717 void CheckVisitedResources() {
16718 for (int i = 0; i < 4; i++) {
16719 CHECK(found_resource_[i]);
16724 v8::String::ExternalStringResource* resource_[4];
16725 bool found_resource_[4];
16729 TEST(VisitExternalStrings) {
16731 v8::HandleScope scope(env->GetIsolate());
16732 const char* string = "Some string";
16733 uint16_t* two_byte_string = AsciiToTwoByteString(string);
16734 TestResource* resource[4];
16735 resource[0] = new TestResource(two_byte_string);
16736 v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]);
16737 resource[1] = new TestResource(two_byte_string);
16738 v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]);
16740 // Externalized symbol.
16741 resource[2] = new TestResource(two_byte_string);
16742 v8::Local<v8::String> string2 = v8::String::NewSymbol(string);
16743 CHECK(string2->MakeExternal(resource[2]));
16745 // Symbolized External.
16746 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
16747 v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]);
16748 HEAP->CollectAllAvailableGarbage(); // Tenure string.
16749 // Turn into a symbol.
16750 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
16751 CHECK(!HEAP->InternalizeString(*string3_i)->IsFailure());
16752 CHECK(string3_i->IsInternalizedString());
16754 // We need to add usages for string* to avoid warnings in GCC 4.7
16755 CHECK(string0->IsExternal());
16756 CHECK(string1->IsExternal());
16757 CHECK(string2->IsExternal());
16758 CHECK(string3->IsExternal());
16760 VisitorImpl visitor(resource);
16761 v8::V8::VisitExternalResources(&visitor);
16762 visitor.CheckVisitedResources();
16766 static double DoubleFromBits(uint64_t value) {
16768 i::OS::MemCopy(&target, &value, sizeof(target));
16773 static uint64_t DoubleToBits(double value) {
16775 i::OS::MemCopy(&target, &value, sizeof(target));
16780 static double DoubleToDateTime(double input) {
16781 double date_limit = 864e13;
16782 if (std::isnan(input) || input < -date_limit || input > date_limit) {
16783 return i::OS::nan_value();
16785 return (input < 0) ? -(floor(-input)) : floor(input);
16789 // We don't have a consistent way to write 64-bit constants syntactically, so we
16790 // split them into two 32-bit constants and combine them programmatically.
16791 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
16792 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
16796 THREADED_TEST(QuietSignalingNaNs) {
16797 LocalContext context;
16798 v8::HandleScope scope(context->GetIsolate());
16799 v8::TryCatch try_catch;
16801 // Special double values.
16802 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
16803 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
16804 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
16805 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
16806 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
16807 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
16808 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
16810 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
16811 // on either side of the epoch.
16812 double date_limit = 864e13;
16814 double test_values[] = {
16836 int num_test_values = 20;
16838 for (int i = 0; i < num_test_values; i++) {
16839 double test_value = test_values[i];
16841 // Check that Number::New preserves non-NaNs and quiets SNaNs.
16842 v8::Handle<v8::Value> number = v8::Number::New(test_value);
16843 double stored_number = number->NumberValue();
16844 if (!std::isnan(test_value)) {
16845 CHECK_EQ(test_value, stored_number);
16847 uint64_t stored_bits = DoubleToBits(stored_number);
16848 // Check if quiet nan (bits 51..62 all set).
16849 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
16850 // Most significant fraction bit for quiet nan is set to 0
16851 // on MIPS architecture. Allowed by IEEE-754.
16852 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
16854 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
16858 // Check that Date::New preserves non-NaNs in the date range and
16860 v8::Handle<v8::Value> date = v8::Date::New(test_value);
16861 double expected_stored_date = DoubleToDateTime(test_value);
16862 double stored_date = date->NumberValue();
16863 if (!std::isnan(expected_stored_date)) {
16864 CHECK_EQ(expected_stored_date, stored_date);
16866 uint64_t stored_bits = DoubleToBits(stored_date);
16867 // Check if quiet nan (bits 51..62 all set).
16868 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR)
16869 // Most significant fraction bit for quiet nan is set to 0
16870 // on MIPS architecture. Allowed by IEEE-754.
16871 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
16873 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
16880 static void SpaghettiIncident(
16881 const v8::FunctionCallbackInfo<v8::Value>& args) {
16882 v8::HandleScope scope(args.GetIsolate());
16884 v8::Handle<v8::String> str(args[0]->ToString());
16886 if (tc.HasCaught())
16891 // Test that an exception can be propagated down through a spaghetti
16892 // stack using ReThrow.
16893 THREADED_TEST(SpaghettiStackReThrow) {
16894 v8::HandleScope scope(v8::Isolate::GetCurrent());
16895 LocalContext context;
16896 context->Global()->Set(
16897 v8::String::New("s"),
16898 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction());
16899 v8::TryCatch try_catch;
16903 " toString: function () {"
16913 CHECK(try_catch.HasCaught());
16914 v8::String::Utf8Value value(try_catch.Exception());
16915 CHECK_EQ(0, strcmp(*value, "Hey!"));
16920 v8::V8::Initialize();
16921 v8::Isolate* isolate = v8::Isolate::GetCurrent();
16922 v8::HandleScope scope(isolate);
16923 v8::Local<Context> other_context;
16926 // Create a context used to keep the code from aging in the compilation
16928 other_context = Context::New(isolate);
16930 // Context-dependent context data creates reference from the compilation
16931 // cache to the global object.
16932 const char* source_simple = "1";
16934 v8::HandleScope scope(isolate);
16935 v8::Local<Context> context = Context::New(isolate);
16938 Local<v8::String> obj = v8::String::New("");
16939 context->SetEmbedderData(0, obj);
16940 CompileRun(source_simple);
16943 v8::V8::ContextDisposedNotification();
16944 for (gc_count = 1; gc_count < 10; gc_count++) {
16945 other_context->Enter();
16946 CompileRun(source_simple);
16947 other_context->Exit();
16948 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
16949 if (GetGlobalObjectsCount() == 1) break;
16951 CHECK_GE(2, gc_count);
16952 CHECK_EQ(1, GetGlobalObjectsCount());
16954 // Eval in a function creates reference from the compilation cache to the
16956 const char* source_eval = "function f(){eval('1')}; f()";
16958 v8::HandleScope scope(isolate);
16959 v8::Local<Context> context = Context::New(isolate);
16962 CompileRun(source_eval);
16965 v8::V8::ContextDisposedNotification();
16966 for (gc_count = 1; gc_count < 10; gc_count++) {
16967 other_context->Enter();
16968 CompileRun(source_eval);
16969 other_context->Exit();
16970 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
16971 if (GetGlobalObjectsCount() == 1) break;
16973 CHECK_GE(2, gc_count);
16974 CHECK_EQ(1, GetGlobalObjectsCount());
16976 // Looking up the line number for an exception creates reference from the
16977 // compilation cache to the global object.
16978 const char* source_exception = "function f(){throw 1;} f()";
16980 v8::HandleScope scope(isolate);
16981 v8::Local<Context> context = Context::New(isolate);
16984 v8::TryCatch try_catch;
16985 CompileRun(source_exception);
16986 CHECK(try_catch.HasCaught());
16987 v8::Handle<v8::Message> message = try_catch.Message();
16988 CHECK(!message.IsEmpty());
16989 CHECK_EQ(1, message->GetLineNumber());
16992 v8::V8::ContextDisposedNotification();
16993 for (gc_count = 1; gc_count < 10; gc_count++) {
16994 other_context->Enter();
16995 CompileRun(source_exception);
16996 other_context->Exit();
16997 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
16998 if (GetGlobalObjectsCount() == 1) break;
17000 CHECK_GE(2, gc_count);
17001 CHECK_EQ(1, GetGlobalObjectsCount());
17003 v8::V8::ContextDisposedNotification();
17007 THREADED_TEST(ScriptOrigin) {
17009 v8::HandleScope scope(env->GetIsolate());
17010 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17011 v8::Handle<v8::String> script = v8::String::New(
17012 "function f() {}\n\nfunction g() {}");
17013 v8::Script::Compile(script, &origin)->Run();
17014 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17015 env->Global()->Get(v8::String::New("f")));
17016 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17017 env->Global()->Get(v8::String::New("g")));
17019 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
17020 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
17021 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
17023 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
17024 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
17025 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
17029 THREADED_TEST(FunctionGetInferredName) {
17031 v8::HandleScope scope(env->GetIsolate());
17032 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17033 v8::Handle<v8::String> script = v8::String::New(
17034 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
17035 v8::Script::Compile(script, &origin)->Run();
17036 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17037 env->Global()->Get(v8::String::New("f")));
17038 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
17042 THREADED_TEST(ScriptLineNumber) {
17044 v8::HandleScope scope(env->GetIsolate());
17045 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"));
17046 v8::Handle<v8::String> script = v8::String::New(
17047 "function f() {}\n\nfunction g() {}");
17048 v8::Script::Compile(script, &origin)->Run();
17049 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
17050 env->Global()->Get(v8::String::New("f")));
17051 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
17052 env->Global()->Get(v8::String::New("g")));
17053 CHECK_EQ(0, f->GetScriptLineNumber());
17054 CHECK_EQ(2, g->GetScriptLineNumber());
17058 THREADED_TEST(ScriptColumnNumber) {
17060 v8::HandleScope scope(env->GetIsolate());
17061 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
17062 v8::Integer::New(3), v8::Integer::New(2));
17063 v8::Handle<v8::String> script = v8::String::New(
17064 "function foo() {}\n\n function bar() {}");
17065 v8::Script::Compile(script, &origin)->Run();
17066 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
17067 env->Global()->Get(v8::String::New("foo")));
17068 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
17069 env->Global()->Get(v8::String::New("bar")));
17070 CHECK_EQ(14, foo->GetScriptColumnNumber());
17071 CHECK_EQ(17, bar->GetScriptColumnNumber());
17075 THREADED_TEST(FunctionGetScriptId) {
17077 v8::HandleScope scope(env->GetIsolate());
17078 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"),
17079 v8::Integer::New(3), v8::Integer::New(2));
17080 v8::Handle<v8::String> scriptSource = v8::String::New(
17081 "function foo() {}\n\n function bar() {}");
17082 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
17084 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
17085 env->Global()->Get(v8::String::New("foo")));
17086 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
17087 env->Global()->Get(v8::String::New("bar")));
17088 CHECK_EQ(script->Id(), foo->GetScriptId());
17089 CHECK_EQ(script->Id(), bar->GetScriptId());
17093 static void GetterWhichReturns42(
17094 Local<String> name,
17095 const v8::PropertyCallbackInfo<v8::Value>& info) {
17096 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17097 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17098 info.GetReturnValue().Set(v8_num(42));
17102 static void SetterWhichSetsYOnThisTo23(
17103 Local<String> name,
17104 Local<Value> value,
17105 const v8::PropertyCallbackInfo<void>& info) {
17106 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17107 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17108 info.This()->Set(v8_str("y"), v8_num(23));
17112 void FooGetInterceptor(Local<String> name,
17113 const v8::PropertyCallbackInfo<v8::Value>& info) {
17114 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17115 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17116 if (!name->Equals(v8_str("foo"))) return;
17117 info.GetReturnValue().Set(v8_num(42));
17121 void FooSetInterceptor(Local<String> name,
17122 Local<Value> value,
17123 const v8::PropertyCallbackInfo<v8::Value>& info) {
17124 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
17125 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
17126 if (!name->Equals(v8_str("foo"))) return;
17127 info.This()->Set(v8_str("y"), v8_num(23));
17128 info.GetReturnValue().Set(v8_num(23));
17132 TEST(SetterOnConstructorPrototype) {
17133 v8::HandleScope scope(v8::Isolate::GetCurrent());
17134 Local<ObjectTemplate> templ = ObjectTemplate::New();
17135 templ->SetAccessor(v8_str("x"),
17136 GetterWhichReturns42,
17137 SetterWhichSetsYOnThisTo23);
17138 LocalContext context;
17139 context->Global()->Set(v8_str("P"), templ->NewInstance());
17140 CompileRun("function C1() {"
17143 "C1.prototype = P;"
17147 "C2.prototype = { };"
17148 "C2.prototype.__proto__ = P;");
17150 v8::Local<v8::Script> script;
17151 script = v8::Script::Compile(v8_str("new C1();"));
17152 for (int i = 0; i < 10; i++) {
17153 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17154 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
17155 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
17158 script = v8::Script::Compile(v8_str("new C2();"));
17159 for (int i = 0; i < 10; i++) {
17160 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
17161 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
17162 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
17167 static void NamedPropertyGetterWhichReturns42(
17168 Local<String> name,
17169 const v8::PropertyCallbackInfo<v8::Value>& info) {
17170 info.GetReturnValue().Set(v8_num(42));
17174 static void NamedPropertySetterWhichSetsYOnThisTo23(
17175 Local<String> name,
17176 Local<Value> value,
17177 const v8::PropertyCallbackInfo<v8::Value>& info) {
17178 if (name->Equals(v8_str("x"))) {
17179 info.This()->Set(v8_str("y"), v8_num(23));
17184 THREADED_TEST(InterceptorOnConstructorPrototype) {
17185 v8::HandleScope scope(v8::Isolate::GetCurrent());
17186 Local<ObjectTemplate> templ = ObjectTemplate::New();
17187 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
17188 NamedPropertySetterWhichSetsYOnThisTo23);
17189 LocalContext context;
17190 context->Global()->Set(v8_str("P"), templ->NewInstance());
17191 CompileRun("function C1() {"
17194 "C1.prototype = P;"
17198 "C2.prototype = { };"
17199 "C2.prototype.__proto__ = P;");
17201 v8::Local<v8::Script> script;
17202 script = v8::Script::Compile(v8_str("new C1();"));
17203 for (int i = 0; i < 10; i++) {
17204 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17205 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
17206 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
17209 script = v8::Script::Compile(v8_str("new C2();"));
17210 for (int i = 0; i < 10; i++) {
17211 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
17212 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
17213 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
17219 const char* source = "function C1() {"
17222 "C1.prototype = P;";
17224 LocalContext context;
17225 v8::HandleScope scope(context->GetIsolate());
17226 v8::Local<v8::Script> script;
17228 // Use a simple object as prototype.
17229 v8::Local<v8::Object> prototype = v8::Object::New();
17230 prototype->Set(v8_str("y"), v8_num(42));
17231 context->Global()->Set(v8_str("P"), prototype);
17233 // This compile will add the code to the compilation cache.
17234 CompileRun(source);
17236 script = v8::Script::Compile(v8_str("new C1();"));
17237 // Allow enough iterations for the inobject slack tracking logic
17238 // to finalize instance size and install the fast construct stub.
17239 for (int i = 0; i < 256; i++) {
17240 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17241 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
17242 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
17245 // Use an API object with accessors as prototype.
17246 Local<ObjectTemplate> templ = ObjectTemplate::New();
17247 templ->SetAccessor(v8_str("x"),
17248 GetterWhichReturns42,
17249 SetterWhichSetsYOnThisTo23);
17250 context->Global()->Set(v8_str("P"), templ->NewInstance());
17252 // This compile will get the code from the compilation cache.
17253 CompileRun(source);
17255 script = v8::Script::Compile(v8_str("new C1();"));
17256 for (int i = 0; i < 10; i++) {
17257 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
17258 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
17259 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
17263 int prologue_call_count = 0;
17264 int epilogue_call_count = 0;
17265 int prologue_call_count_second = 0;
17266 int epilogue_call_count_second = 0;
17268 void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
17269 ++prologue_call_count;
17273 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
17274 ++epilogue_call_count;
17278 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
17279 ++prologue_call_count_second;
17283 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
17284 ++epilogue_call_count_second;
17288 TEST(GCCallbacks) {
17289 LocalContext context;
17291 v8::V8::AddGCPrologueCallback(PrologueCallback);
17292 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
17293 CHECK_EQ(0, prologue_call_count);
17294 CHECK_EQ(0, epilogue_call_count);
17295 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17296 CHECK_EQ(1, prologue_call_count);
17297 CHECK_EQ(1, epilogue_call_count);
17298 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
17299 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
17300 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17301 CHECK_EQ(2, prologue_call_count);
17302 CHECK_EQ(2, epilogue_call_count);
17303 CHECK_EQ(1, prologue_call_count_second);
17304 CHECK_EQ(1, epilogue_call_count_second);
17305 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
17306 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
17307 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17308 CHECK_EQ(2, prologue_call_count);
17309 CHECK_EQ(2, epilogue_call_count);
17310 CHECK_EQ(2, prologue_call_count_second);
17311 CHECK_EQ(2, epilogue_call_count_second);
17312 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
17313 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17314 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17315 CHECK_EQ(2, prologue_call_count);
17316 CHECK_EQ(2, epilogue_call_count);
17317 CHECK_EQ(2, prologue_call_count_second);
17318 CHECK_EQ(2, epilogue_call_count_second);
17322 THREADED_TEST(AddToJSFunctionResultCache) {
17323 i::FLAG_stress_compaction = false;
17324 i::FLAG_allow_natives_syntax = true;
17325 v8::HandleScope scope(v8::Isolate::GetCurrent());
17327 LocalContext context;
17333 " var r0 = %_GetFromCache(0, key0);"
17334 " var r1 = %_GetFromCache(0, key1);"
17335 " var r0_ = %_GetFromCache(0, key0);"
17337 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
17338 " var r1_ = %_GetFromCache(0, key1);"
17340 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
17341 " return 'PASSED';"
17343 HEAP->ClearJSFunctionResultCaches();
17344 ExpectString(code, "PASSED");
17348 static const int k0CacheSize = 16;
17350 THREADED_TEST(FillJSFunctionResultCache) {
17351 i::FLAG_allow_natives_syntax = true;
17352 LocalContext context;
17353 v8::HandleScope scope(context->GetIsolate());
17358 " var r = %_GetFromCache(0, k);"
17359 " for (var i = 0; i < 16; i++) {"
17360 " %_GetFromCache(0, 'a' + i);"
17362 " if (r === %_GetFromCache(0, k))"
17363 " return 'FAILED: k0CacheSize is too small';"
17364 " return 'PASSED';"
17366 HEAP->ClearJSFunctionResultCaches();
17367 ExpectString(code, "PASSED");
17371 THREADED_TEST(RoundRobinGetFromCache) {
17372 i::FLAG_allow_natives_syntax = true;
17373 LocalContext context;
17374 v8::HandleScope scope(context->GetIsolate());
17379 " for (var i = 0; i < 16; i++) keys.push(i);"
17380 " var values = [];"
17381 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17382 " for (var i = 0; i < 16; i++) {"
17383 " var v = %_GetFromCache(0, keys[i]);"
17384 " if (v.toString() !== values[i].toString())"
17385 " return 'Wrong value for ' + "
17386 " keys[i] + ': ' + v + ' vs. ' + values[i];"
17388 " return 'PASSED';"
17390 HEAP->ClearJSFunctionResultCaches();
17391 ExpectString(code, "PASSED");
17395 THREADED_TEST(ReverseGetFromCache) {
17396 i::FLAG_allow_natives_syntax = true;
17397 LocalContext context;
17398 v8::HandleScope scope(context->GetIsolate());
17403 " for (var i = 0; i < 16; i++) keys.push(i);"
17404 " var values = [];"
17405 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17406 " for (var i = 15; i >= 16; i--) {"
17407 " var v = %_GetFromCache(0, keys[i]);"
17408 " if (v !== values[i])"
17409 " return 'Wrong value for ' + "
17410 " keys[i] + ': ' + v + ' vs. ' + values[i];"
17412 " return 'PASSED';"
17414 HEAP->ClearJSFunctionResultCaches();
17415 ExpectString(code, "PASSED");
17419 THREADED_TEST(TestEviction) {
17420 i::FLAG_allow_natives_syntax = true;
17421 LocalContext context;
17422 v8::HandleScope scope(context->GetIsolate());
17426 " for (var i = 0; i < 2*16; i++) {"
17427 " %_GetFromCache(0, 'a' + i);"
17429 " return 'PASSED';"
17431 HEAP->ClearJSFunctionResultCaches();
17432 ExpectString(code, "PASSED");
17436 THREADED_TEST(TwoByteStringInAsciiCons) {
17437 // See Chromium issue 47824.
17438 LocalContext context;
17439 v8::HandleScope scope(context->GetIsolate());
17441 const char* init_code =
17442 "var str1 = 'abelspendabel';"
17443 "var str2 = str1 + str1 + str1;"
17445 Local<Value> result = CompileRun(init_code);
17447 Local<Value> indexof = CompileRun("str2.indexOf('els')");
17448 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
17450 CHECK(result->IsString());
17451 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
17452 int length = string->length();
17453 CHECK(string->IsOneByteRepresentation());
17455 FlattenString(string);
17456 i::Handle<i::String> flat_string = FlattenGetString(string);
17458 CHECK(string->IsOneByteRepresentation());
17459 CHECK(flat_string->IsOneByteRepresentation());
17461 // Create external resource.
17462 uint16_t* uc16_buffer = new uint16_t[length + 1];
17464 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
17465 uc16_buffer[length] = 0;
17467 TestResource resource(uc16_buffer);
17469 flat_string->MakeExternal(&resource);
17471 CHECK(flat_string->IsTwoByteRepresentation());
17473 // If the cons string has been short-circuited, skip the following checks.
17474 if (!string.is_identical_to(flat_string)) {
17475 // At this point, we should have a Cons string which is flat and ASCII,
17476 // with a first half that is a two-byte string (although it only contains
17477 // ASCII characters). This is a valid sequence of steps, and it can happen
17479 CHECK(string->IsOneByteRepresentation());
17480 i::ConsString* cons = i::ConsString::cast(*string);
17481 CHECK_EQ(0, cons->second()->length());
17482 CHECK(cons->first()->IsTwoByteRepresentation());
17485 // Check that some string operations work.
17488 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
17489 CHECK_EQ(6, reresult->Int32Value());
17492 reresult = CompileRun("str2.match(/abe./g).length;");
17493 CHECK_EQ(6, reresult->Int32Value());
17495 reresult = CompileRun("str2.search(/bel/g);");
17496 CHECK_EQ(1, reresult->Int32Value());
17498 reresult = CompileRun("str2.search(/be./g);");
17499 CHECK_EQ(1, reresult->Int32Value());
17501 ExpectTrue("/bel/g.test(str2);");
17503 ExpectTrue("/be./g.test(str2);");
17505 reresult = CompileRun("/bel/g.exec(str2);");
17506 CHECK(!reresult->IsNull());
17508 reresult = CompileRun("/be./g.exec(str2);");
17509 CHECK(!reresult->IsNull());
17511 ExpectString("str2.substring(2, 10);", "elspenda");
17513 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
17515 ExpectString("str2.charAt(2);", "e");
17517 ExpectObject("str2.indexOf('els');", indexof);
17519 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
17521 reresult = CompileRun("str2.charCodeAt(2);");
17522 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
17526 TEST(ContainsOnlyOneByte) {
17527 v8::V8::Initialize();
17528 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17529 v8::HandleScope scope(isolate);
17530 // Make a buffer long enough that it won't automatically be converted.
17531 const int length = 512;
17532 // Ensure word aligned assignment.
17533 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
17534 i::SmartArrayPointer<uintptr_t>
17535 aligned_contents(new uintptr_t[aligned_length]);
17536 uint16_t* string_contents = reinterpret_cast<uint16_t*>(*aligned_contents);
17537 // Set to contain only one byte.
17538 for (int i = 0; i < length-1; i++) {
17539 string_contents[i] = 0x41;
17541 string_contents[length-1] = 0;
17543 Handle<String> string;
17544 string = String::NewExternal(new TestResource(string_contents));
17545 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17546 // Counter example.
17547 string = String::NewFromTwoByte(isolate, string_contents);
17548 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17549 // Test left right and balanced cons strings.
17550 Handle<String> base = String::NewFromUtf8(isolate, "a");
17551 Handle<String> left = base;
17552 Handle<String> right = base;
17553 for (int i = 0; i < 1000; i++) {
17554 left = String::Concat(base, left);
17555 right = String::Concat(right, base);
17557 Handle<String> balanced = String::Concat(left, base);
17558 balanced = String::Concat(balanced, right);
17559 Handle<String> cons_strings[] = {left, balanced, right};
17560 Handle<String> two_byte =
17561 String::NewExternal(new TestResource(string_contents));
17562 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) {
17563 // Base assumptions.
17564 string = cons_strings[i];
17565 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17566 // Test left and right concatentation.
17567 string = String::Concat(two_byte, cons_strings[i]);
17568 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17569 string = String::Concat(cons_strings[i], two_byte);
17570 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17572 // Set bits in different positions
17573 // for strings of different lengths and alignments.
17574 for (int alignment = 0; alignment < 7; alignment++) {
17575 for (int size = 2; alignment + size < length; size *= 2) {
17576 int zero_offset = size + alignment;
17577 string_contents[zero_offset] = 0;
17578 for (int i = 0; i < size; i++) {
17579 int shift = 8 + (i % 7);
17580 string_contents[alignment + i] = 1 << shift;
17582 String::NewExternal(new TestResource(string_contents + alignment));
17583 CHECK_EQ(size, string->Length());
17584 CHECK(!string->ContainsOnlyOneByte());
17585 string_contents[alignment + i] = 0x41;
17587 string_contents[zero_offset] = 0x41;
17593 // Failed access check callback that performs a GC on each invocation.
17594 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
17595 v8::AccessType type,
17596 Local<v8::Value> data) {
17597 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
17601 TEST(GCInFailedAccessCheckCallback) {
17602 // Install a failed access check callback that performs a GC on each
17603 // invocation. Then force the callback to be called from va
17605 v8::V8::Initialize();
17606 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
17608 v8::HandleScope scope(v8::Isolate::GetCurrent());
17610 // Create an ObjectTemplate for global objects and install access
17611 // check callbacks that will block access.
17612 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
17613 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
17614 IndexedGetAccessBlocker,
17615 v8::Handle<v8::Value>(),
17618 // Create a context and set an x property on it's global object.
17619 LocalContext context0(NULL, global_template);
17620 context0->Global()->Set(v8_str("x"), v8_num(42));
17621 v8::Handle<v8::Object> global0 = context0->Global();
17623 // Create a context with a different security token so that the
17624 // failed access check callback will be called on each access.
17625 LocalContext context1(NULL, global_template);
17626 context1->Global()->Set(v8_str("other"), global0);
17628 // Get property with failed access check.
17629 ExpectUndefined("other.x");
17631 // Get element with failed access check.
17632 ExpectUndefined("other[0]");
17634 // Set property with failed access check.
17635 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
17636 CHECK(result->IsObject());
17638 // Set element with failed access check.
17639 result = CompileRun("other[0] = new Object()");
17640 CHECK(result->IsObject());
17642 // Get property attribute with failed access check.
17643 ExpectFalse("\'x\' in other");
17645 // Get property attribute for element with failed access check.
17646 ExpectFalse("0 in other");
17648 // Delete property.
17649 ExpectFalse("delete other.x");
17652 CHECK_EQ(false, global0->Delete(0));
17656 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
17658 // Define JavaScript accessor.
17659 ExpectUndefined("Object.prototype.__defineGetter__.call("
17660 " other, \'x\', function() { return 42; })");
17663 ExpectUndefined("Object.prototype.__lookupGetter__.call("
17666 // HasLocalElement.
17667 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
17669 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
17670 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
17671 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
17673 // Reset the failed access check callback so it does not influence
17674 // the other tests.
17675 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
17679 TEST(DefaultIsolateGetCurrent) {
17680 CHECK(v8::Isolate::GetCurrent() != NULL);
17681 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17682 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
17683 printf("*** %s\n", "DefaultIsolateGetCurrent success");
17687 TEST(IsolateNewDispose) {
17688 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
17689 v8::Isolate* isolate = v8::Isolate::New();
17690 CHECK(isolate != NULL);
17691 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
17692 CHECK(current_isolate != isolate);
17693 CHECK(current_isolate == v8::Isolate::GetCurrent());
17695 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17696 last_location = last_message = NULL;
17697 isolate->Dispose();
17698 CHECK_EQ(last_location, NULL);
17699 CHECK_EQ(last_message, NULL);
17703 TEST(IsolateEnterExitDefault) {
17704 v8::Isolate* current_isolate = v8::Isolate::GetCurrent();
17705 CHECK(current_isolate != NULL); // Default isolate.
17706 v8::HandleScope scope(current_isolate);
17707 LocalContext context;
17708 ExpectString("'hello'", "hello");
17709 current_isolate->Enter();
17710 ExpectString("'still working'", "still working");
17711 current_isolate->Exit();
17712 ExpectString("'still working 2'", "still working 2");
17713 current_isolate->Exit();
17714 // Default isolate is always, well, 'default current'.
17715 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate);
17716 // Still working since default isolate is auto-entering any thread
17717 // that has no isolate and attempts to execute V8 APIs.
17718 ExpectString("'still working 3'", "still working 3");
17722 TEST(DisposeDefaultIsolate) {
17723 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17725 // Run some V8 code to trigger default isolate to become 'current'.
17726 v8::HandleScope scope(v8::Isolate::GetCurrent());
17727 LocalContext context;
17728 ExpectString("'run some V8'", "run some V8");
17730 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17731 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate());
17732 last_location = last_message = NULL;
17733 isolate->Dispose();
17734 // It is not possible to dispose default isolate via Isolate API.
17735 CHECK_NE(last_location, NULL);
17736 CHECK_NE(last_message, NULL);
17740 TEST(RunDefaultAndAnotherIsolate) {
17741 v8::HandleScope scope(v8::Isolate::GetCurrent());
17742 LocalContext context;
17744 // Enter new isolate.
17745 v8::Isolate* isolate = v8::Isolate::New();
17748 { // Need this block because subsequent Exit() will deallocate Heap,
17749 // so we need all scope objects to be deconstructed when it happens.
17750 v8::HandleScope scope_new(isolate);
17751 LocalContext context_new;
17753 // Run something in new isolate.
17754 CompileRun("var foo = 153;");
17755 ExpectTrue("function f() { return foo == 153; }; f()");
17759 // This runs automatically in default isolate.
17760 // Variables in another isolate should be not available.
17761 ExpectTrue("function f() {"
17772 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17773 last_location = last_message = NULL;
17774 isolate->Dispose();
17775 CHECK_EQ(last_location, NULL);
17776 CHECK_EQ(last_message, NULL);
17778 // Check that default isolate still runs.
17779 ExpectTrue("function f() { return bar == 371; }; f()");
17783 TEST(DisposeIsolateWhenInUse) {
17784 v8::Isolate* isolate = v8::Isolate::New();
17787 v8::HandleScope scope(isolate);
17788 LocalContext context;
17789 // Run something in this isolate.
17790 ExpectTrue("true");
17791 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17792 last_location = last_message = NULL;
17793 // Still entered, should fail.
17794 isolate->Dispose();
17795 CHECK_NE(last_location, NULL);
17796 CHECK_NE(last_message, NULL);
17800 TEST(RunTwoIsolatesOnSingleThread) {
17802 v8::Isolate* isolate1 = v8::Isolate::New();
17804 v8::Persistent<v8::Context> context1;
17806 v8::HandleScope scope(isolate1);
17807 context1.Reset(isolate1, Context::New(isolate1));
17811 v8::HandleScope scope(isolate1);
17812 v8::Local<v8::Context> context =
17813 v8::Local<v8::Context>::New(isolate1, context1);
17814 v8::Context::Scope context_scope(context);
17815 // Run something in new isolate.
17816 CompileRun("var foo = 'isolate 1';");
17817 ExpectString("function f() { return foo; }; f()", "isolate 1");
17821 v8::Isolate* isolate2 = v8::Isolate::New();
17822 v8::Persistent<v8::Context> context2;
17825 v8::Isolate::Scope iscope(isolate2);
17826 v8::HandleScope scope(isolate2);
17827 context2.Reset(isolate2, Context::New(isolate2));
17828 v8::Local<v8::Context> context =
17829 v8::Local<v8::Context>::New(isolate2, context2);
17830 v8::Context::Scope context_scope(context);
17832 // Run something in new isolate.
17833 CompileRun("var foo = 'isolate 2';");
17834 ExpectString("function f() { return foo; }; f()", "isolate 2");
17838 v8::HandleScope scope(isolate1);
17839 v8::Local<v8::Context> context =
17840 v8::Local<v8::Context>::New(isolate1, context1);
17841 v8::Context::Scope context_scope(context);
17842 // Now again in isolate 1
17843 ExpectString("function f() { return foo; }; f()", "isolate 1");
17848 // Run some stuff in default isolate.
17849 v8::Persistent<v8::Context> context_default;
17851 v8::Isolate* isolate = v8::Isolate::GetCurrent();
17852 v8::Isolate::Scope iscope(isolate);
17853 v8::HandleScope scope(isolate);
17854 context_default.Reset(isolate, Context::New(isolate));
17858 v8::HandleScope scope(v8::Isolate::GetCurrent());
17859 v8::Local<v8::Context> context =
17860 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context_default);
17861 v8::Context::Scope context_scope(context);
17862 // Variables in other isolates should be not available, verify there
17863 // is an exception.
17864 ExpectTrue("function f() {"
17872 "var isDefaultIsolate = true;"
17879 v8::Isolate::Scope iscope(isolate2);
17880 v8::HandleScope scope(v8::Isolate::GetCurrent());
17881 v8::Local<v8::Context> context =
17882 v8::Local<v8::Context>::New(isolate2, context2);
17883 v8::Context::Scope context_scope(context);
17884 ExpectString("function f() { return foo; }; f()", "isolate 2");
17888 v8::HandleScope scope(v8::Isolate::GetCurrent());
17889 v8::Local<v8::Context> context =
17890 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
17891 v8::Context::Scope context_scope(context);
17892 ExpectString("function f() { return foo; }; f()", "isolate 1");
17896 v8::Isolate::Scope iscope(isolate2);
17897 context2.Dispose();
17900 context1.Dispose();
17903 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17904 last_location = last_message = NULL;
17906 isolate1->Dispose();
17907 CHECK_EQ(last_location, NULL);
17908 CHECK_EQ(last_message, NULL);
17910 isolate2->Dispose();
17911 CHECK_EQ(last_location, NULL);
17912 CHECK_EQ(last_message, NULL);
17914 // Check that default isolate still runs.
17916 v8::HandleScope scope(v8::Isolate::GetCurrent());
17917 v8::Local<v8::Context> context =
17918 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context_default);
17919 v8::Context::Scope context_scope(context);
17920 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
17925 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
17926 v8::Isolate::Scope isolate_scope(isolate);
17927 v8::HandleScope scope(isolate);
17928 LocalContext context;
17929 i::ScopedVector<char> code(1024);
17930 i::OS::SNPrintF(code, "function fib(n) {"
17931 " if (n <= 2) return 1;"
17932 " return fib(n-1) + fib(n-2);"
17935 Local<Value> value = CompileRun(code.start());
17936 CHECK(value->IsNumber());
17937 return static_cast<int>(value->NumberValue());
17940 class IsolateThread : public v8::internal::Thread {
17942 IsolateThread(v8::Isolate* isolate, int fib_limit)
17943 : Thread("IsolateThread"),
17945 fib_limit_(fib_limit),
17949 result_ = CalcFibonacci(isolate_, fib_limit_);
17952 int result() { return result_; }
17955 v8::Isolate* isolate_;
17961 TEST(MultipleIsolatesOnIndividualThreads) {
17962 v8::Isolate* isolate1 = v8::Isolate::New();
17963 v8::Isolate* isolate2 = v8::Isolate::New();
17965 IsolateThread thread1(isolate1, 21);
17966 IsolateThread thread2(isolate2, 12);
17968 // Compute some fibonacci numbers on 3 threads in 3 isolates.
17972 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21);
17973 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12);
17978 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
17979 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
17980 CHECK_EQ(result1, 10946);
17981 CHECK_EQ(result2, 144);
17982 CHECK_EQ(result1, thread1.result());
17983 CHECK_EQ(result2, thread2.result());
17985 isolate1->Dispose();
17986 isolate2->Dispose();
17990 TEST(IsolateDifferentContexts) {
17991 v8::Isolate* isolate = v8::Isolate::New();
17992 Local<v8::Context> context;
17994 v8::Isolate::Scope isolate_scope(isolate);
17995 v8::HandleScope handle_scope(isolate);
17996 context = v8::Context::New(isolate);
17997 v8::Context::Scope context_scope(context);
17998 Local<Value> v = CompileRun("2");
17999 CHECK(v->IsNumber());
18000 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
18003 v8::Isolate::Scope isolate_scope(isolate);
18004 v8::HandleScope handle_scope(isolate);
18005 context = v8::Context::New(isolate);
18006 v8::Context::Scope context_scope(context);
18007 Local<Value> v = CompileRun("22");
18008 CHECK(v->IsNumber());
18009 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
18013 class InitDefaultIsolateThread : public v8::internal::Thread {
18017 SetResourceConstraints,
18019 SetCounterFunction,
18020 SetCreateHistogramFunction,
18021 SetAddHistogramSampleFunction
18024 explicit InitDefaultIsolateThread(TestCase testCase)
18025 : Thread("InitDefaultIsolateThread"),
18026 testCase_(testCase),
18030 switch (testCase_) {
18032 v8::V8::IgnoreOutOfMemoryException();
18035 case SetResourceConstraints: {
18036 static const int K = 1024;
18037 v8::ResourceConstraints constraints;
18038 constraints.set_max_young_space_size(256 * K);
18039 constraints.set_max_old_space_size(4 * K * K);
18040 v8::SetResourceConstraints(&constraints);
18044 case SetFatalHandler:
18045 v8::V8::SetFatalErrorHandler(NULL);
18048 case SetCounterFunction:
18049 v8::V8::SetCounterFunction(NULL);
18052 case SetCreateHistogramFunction:
18053 v8::V8::SetCreateHistogramFunction(NULL);
18056 case SetAddHistogramSampleFunction:
18057 v8::V8::SetAddHistogramSampleFunction(NULL);
18063 bool result() { return result_; }
18066 TestCase testCase_;
18071 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
18072 InitDefaultIsolateThread thread(testCase);
18075 CHECK_EQ(thread.result(), true);
18079 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
18080 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM);
18084 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
18085 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
18089 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
18090 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
18094 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
18095 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
18099 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
18100 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
18104 TEST(InitializeDefaultIsolateOnSecondaryThread6) {
18105 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
18109 TEST(StringCheckMultipleContexts) {
18111 "(function() { return \"a\".charAt(0); })()";
18114 // Run the code twice in the first context to initialize the call IC.
18115 LocalContext context1;
18116 v8::HandleScope scope(context1->GetIsolate());
18117 ExpectString(code, "a");
18118 ExpectString(code, "a");
18122 // Change the String.prototype in the second context and check
18123 // that the right function gets called.
18124 LocalContext context2;
18125 v8::HandleScope scope(context2->GetIsolate());
18126 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
18127 ExpectString(code, "not a");
18132 TEST(NumberCheckMultipleContexts) {
18134 "(function() { return (42).toString(); })()";
18137 // Run the code twice in the first context to initialize the call IC.
18138 LocalContext context1;
18139 v8::HandleScope scope(context1->GetIsolate());
18140 ExpectString(code, "42");
18141 ExpectString(code, "42");
18145 // Change the Number.prototype in the second context and check
18146 // that the right function gets called.
18147 LocalContext context2;
18148 v8::HandleScope scope(context2->GetIsolate());
18149 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
18150 ExpectString(code, "not 42");
18155 TEST(BooleanCheckMultipleContexts) {
18157 "(function() { return true.toString(); })()";
18160 // Run the code twice in the first context to initialize the call IC.
18161 LocalContext context1;
18162 v8::HandleScope scope(context1->GetIsolate());
18163 ExpectString(code, "true");
18164 ExpectString(code, "true");
18168 // Change the Boolean.prototype in the second context and check
18169 // that the right function gets called.
18170 LocalContext context2;
18171 v8::HandleScope scope(context2->GetIsolate());
18172 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
18173 ExpectString(code, "");
18178 TEST(DontDeleteCellLoadIC) {
18179 const char* function_code =
18180 "function readCell() { while (true) { return cell; } }";
18183 // Run the code twice in the first context to initialize the load
18184 // IC for a don't delete cell.
18185 LocalContext context1;
18186 v8::HandleScope scope(context1->GetIsolate());
18187 CompileRun("var cell = \"first\";");
18188 ExpectBoolean("delete cell", false);
18189 CompileRun(function_code);
18190 ExpectString("readCell()", "first");
18191 ExpectString("readCell()", "first");
18195 // Use a deletable cell in the second context.
18196 LocalContext context2;
18197 v8::HandleScope scope(context2->GetIsolate());
18198 CompileRun("cell = \"second\";");
18199 CompileRun(function_code);
18200 ExpectString("readCell()", "second");
18201 ExpectBoolean("delete cell", true);
18202 ExpectString("(function() {"
18204 " return readCell();"
18206 " return e.toString();"
18209 "ReferenceError: cell is not defined");
18210 CompileRun("cell = \"new_second\";");
18211 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
18212 ExpectString("readCell()", "new_second");
18213 ExpectString("readCell()", "new_second");
18218 TEST(DontDeleteCellLoadICForceDelete) {
18219 const char* function_code =
18220 "function readCell() { while (true) { return cell; } }";
18222 // Run the code twice to initialize the load IC for a don't delete
18224 LocalContext context;
18225 v8::HandleScope scope(context->GetIsolate());
18226 CompileRun("var cell = \"value\";");
18227 ExpectBoolean("delete cell", false);
18228 CompileRun(function_code);
18229 ExpectString("readCell()", "value");
18230 ExpectString("readCell()", "value");
18232 // Delete the cell using the API and check the inlined code works
18234 CHECK(context->Global()->ForceDelete(v8_str("cell")));
18235 ExpectString("(function() {"
18237 " return readCell();"
18239 " return e.toString();"
18242 "ReferenceError: cell is not defined");
18246 TEST(DontDeleteCellLoadICAPI) {
18247 const char* function_code =
18248 "function readCell() { while (true) { return cell; } }";
18250 // Run the code twice to initialize the load IC for a don't delete
18251 // cell created using the API.
18252 LocalContext context;
18253 v8::HandleScope scope(context->GetIsolate());
18254 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete);
18255 ExpectBoolean("delete cell", false);
18256 CompileRun(function_code);
18257 ExpectString("readCell()", "value");
18258 ExpectString("readCell()", "value");
18260 // Delete the cell using the API and check the inlined code works
18262 CHECK(context->Global()->ForceDelete(v8_str("cell")));
18263 ExpectString("(function() {"
18265 " return readCell();"
18267 " return e.toString();"
18270 "ReferenceError: cell is not defined");
18274 class Visitor42 : public v8::PersistentHandleVisitor {
18276 explicit Visitor42(v8::Persistent<v8::Object>* object)
18277 : counter_(0), object_(object) { }
18279 virtual void VisitPersistentHandle(Persistent<Value>* value,
18280 uint16_t class_id) {
18281 if (class_id != 42) return;
18282 CHECK_EQ(42, value->WrapperClassId());
18283 v8::Isolate* isolate = v8::Isolate::GetCurrent();
18284 v8::HandleScope handle_scope(isolate);
18285 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
18286 v8::Handle<v8::Value> object =
18287 v8::Local<v8::Object>::New(isolate, *object_);
18288 CHECK(handle->IsObject());
18289 CHECK_EQ(Handle<Object>::Cast(handle), object);
18294 v8::Persistent<v8::Object>* object_;
18298 TEST(PersistentHandleVisitor) {
18299 LocalContext context;
18300 v8::Isolate* isolate = context->GetIsolate();
18301 v8::HandleScope scope(isolate);
18302 v8::Persistent<v8::Object> object(isolate, v8::Object::New());
18303 CHECK_EQ(0, object.WrapperClassId(isolate));
18304 object.SetWrapperClassId(isolate, 42);
18305 CHECK_EQ(42, object.WrapperClassId(isolate));
18307 Visitor42 visitor(&object);
18308 v8::V8::VisitHandlesWithClassIds(&visitor);
18309 CHECK_EQ(1, visitor.counter_);
18311 object.Dispose(isolate);
18315 TEST(WrapperClassId) {
18316 LocalContext context;
18317 v8::Isolate* isolate = context->GetIsolate();
18318 v8::HandleScope scope(isolate);
18319 v8::Persistent<v8::Object> object(isolate, v8::Object::New());
18320 CHECK_EQ(0, object.WrapperClassId(isolate));
18321 object.SetWrapperClassId(isolate, 65535);
18322 CHECK_EQ(65535, object.WrapperClassId(isolate));
18323 object.Dispose(isolate);
18327 TEST(PersistentHandleInNewSpaceVisitor) {
18328 LocalContext context;
18329 v8::Isolate* isolate = context->GetIsolate();
18330 v8::HandleScope scope(isolate);
18331 v8::Persistent<v8::Object> object1(isolate, v8::Object::New());
18332 CHECK_EQ(0, object1.WrapperClassId(isolate));
18333 object1.SetWrapperClassId(isolate, 42);
18334 CHECK_EQ(42, object1.WrapperClassId(isolate));
18336 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
18338 v8::Persistent<v8::Object> object2(isolate, v8::Object::New());
18339 CHECK_EQ(0, object2.WrapperClassId(isolate));
18340 object2.SetWrapperClassId(isolate, 42);
18341 CHECK_EQ(42, object2.WrapperClassId(isolate));
18343 Visitor42 visitor(&object2);
18344 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
18345 CHECK_EQ(1, visitor.counter_);
18347 object1.Dispose(isolate);
18348 object2.Dispose(isolate);
18353 LocalContext context;
18354 v8::HandleScope scope(context->GetIsolate());
18356 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
18357 CHECK(re->IsRegExp());
18358 CHECK(re->GetSource()->Equals(v8_str("foo")));
18359 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18361 re = v8::RegExp::New(v8_str("bar"),
18362 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18363 v8::RegExp::kGlobal));
18364 CHECK(re->IsRegExp());
18365 CHECK(re->GetSource()->Equals(v8_str("bar")));
18366 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
18367 static_cast<int>(re->GetFlags()));
18369 re = v8::RegExp::New(v8_str("baz"),
18370 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18371 v8::RegExp::kMultiline));
18372 CHECK(re->IsRegExp());
18373 CHECK(re->GetSource()->Equals(v8_str("baz")));
18374 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18375 static_cast<int>(re->GetFlags()));
18377 re = CompileRun("/quux/").As<v8::RegExp>();
18378 CHECK(re->IsRegExp());
18379 CHECK(re->GetSource()->Equals(v8_str("quux")));
18380 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18382 re = CompileRun("/quux/gm").As<v8::RegExp>();
18383 CHECK(re->IsRegExp());
18384 CHECK(re->GetSource()->Equals(v8_str("quux")));
18385 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
18386 static_cast<int>(re->GetFlags()));
18388 // Override the RegExp constructor and check the API constructor
18390 CompileRun("RegExp = function() {}");
18392 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
18393 CHECK(re->IsRegExp());
18394 CHECK(re->GetSource()->Equals(v8_str("foobar")));
18395 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18397 re = v8::RegExp::New(v8_str("foobarbaz"),
18398 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18399 v8::RegExp::kMultiline));
18400 CHECK(re->IsRegExp());
18401 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
18402 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18403 static_cast<int>(re->GetFlags()));
18405 context->Global()->Set(v8_str("re"), re);
18406 ExpectTrue("re.test('FoobarbaZ')");
18408 // RegExps are objects on which you can set properties.
18409 re->Set(v8_str("property"), v8::Integer::New(32));
18410 v8::Handle<v8::Value> value(CompileRun("re.property"));
18411 CHECK_EQ(32, value->Int32Value());
18413 v8::TryCatch try_catch;
18414 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
18415 CHECK(re.IsEmpty());
18416 CHECK(try_catch.HasCaught());
18417 context->Global()->Set(v8_str("ex"), try_catch.Exception());
18418 ExpectTrue("ex instanceof SyntaxError");
18422 THREADED_TEST(Equals) {
18423 LocalContext localContext;
18424 v8::HandleScope handleScope(localContext->GetIsolate());
18426 v8::Handle<v8::Object> globalProxy = localContext->Global();
18427 v8::Handle<Value> global = globalProxy->GetPrototype();
18429 CHECK(global->StrictEquals(global));
18430 CHECK(!global->StrictEquals(globalProxy));
18431 CHECK(!globalProxy->StrictEquals(global));
18432 CHECK(globalProxy->StrictEquals(globalProxy));
18434 CHECK(global->Equals(global));
18435 CHECK(!global->Equals(globalProxy));
18436 CHECK(!globalProxy->Equals(global));
18437 CHECK(globalProxy->Equals(globalProxy));
18441 static void Getter(v8::Local<v8::String> property,
18442 const v8::PropertyCallbackInfo<v8::Value>& info ) {
18443 info.GetReturnValue().Set(v8_str("42!"));
18447 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
18448 v8::Handle<v8::Array> result = v8::Array::New();
18449 result->Set(0, v8_str("universalAnswer"));
18450 info.GetReturnValue().Set(result);
18454 TEST(NamedEnumeratorAndForIn) {
18455 LocalContext context;
18456 v8::HandleScope handle_scope(context->GetIsolate());
18457 v8::Context::Scope context_scope(context.local());
18459 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New();
18460 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
18461 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
18462 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
18463 "var result = []; for (var k in o) result.push(k); result"));
18464 CHECK_EQ(1, result->Length());
18465 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
18469 TEST(DefinePropertyPostDetach) {
18470 LocalContext context;
18471 v8::HandleScope scope(context->GetIsolate());
18472 v8::Handle<v8::Object> proxy = context->Global();
18473 v8::Handle<v8::Function> define_property =
18474 CompileRun("(function() {"
18475 " Object.defineProperty("
18478 " { configurable: true, enumerable: true, value: 3 });"
18479 "})").As<Function>();
18480 context->DetachGlobal();
18481 define_property->Call(proxy, 0, NULL);
18485 static void InstallContextId(v8::Handle<Context> context, int id) {
18486 Context::Scope scope(context);
18487 CompileRun("Object.prototype").As<Object>()->
18488 Set(v8_str("context_id"), v8::Integer::New(id));
18492 static void CheckContextId(v8::Handle<Object> object, int expected) {
18493 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
18497 THREADED_TEST(CreationContext) {
18498 HandleScope handle_scope(v8::Isolate::GetCurrent());
18499 Handle<Context> context1 = Context::New(v8::Isolate::GetCurrent());
18500 InstallContextId(context1, 1);
18501 Handle<Context> context2 = Context::New(v8::Isolate::GetCurrent());
18502 InstallContextId(context2, 2);
18503 Handle<Context> context3 = Context::New(v8::Isolate::GetCurrent());
18504 InstallContextId(context3, 3);
18506 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New();
18508 Local<Object> object1;
18509 Local<Function> func1;
18511 Context::Scope scope(context1);
18512 object1 = Object::New();
18513 func1 = tmpl->GetFunction();
18516 Local<Object> object2;
18517 Local<Function> func2;
18519 Context::Scope scope(context2);
18520 object2 = Object::New();
18521 func2 = tmpl->GetFunction();
18524 Local<Object> instance1;
18525 Local<Object> instance2;
18528 Context::Scope scope(context3);
18529 instance1 = func1->NewInstance();
18530 instance2 = func2->NewInstance();
18533 CHECK(object1->CreationContext() == context1);
18534 CheckContextId(object1, 1);
18535 CHECK(func1->CreationContext() == context1);
18536 CheckContextId(func1, 1);
18537 CHECK(instance1->CreationContext() == context1);
18538 CheckContextId(instance1, 1);
18539 CHECK(object2->CreationContext() == context2);
18540 CheckContextId(object2, 2);
18541 CHECK(func2->CreationContext() == context2);
18542 CheckContextId(func2, 2);
18543 CHECK(instance2->CreationContext() == context2);
18544 CheckContextId(instance2, 2);
18547 Context::Scope scope(context1);
18548 CHECK(object1->CreationContext() == context1);
18549 CheckContextId(object1, 1);
18550 CHECK(func1->CreationContext() == context1);
18551 CheckContextId(func1, 1);
18552 CHECK(instance1->CreationContext() == context1);
18553 CheckContextId(instance1, 1);
18554 CHECK(object2->CreationContext() == context2);
18555 CheckContextId(object2, 2);
18556 CHECK(func2->CreationContext() == context2);
18557 CheckContextId(func2, 2);
18558 CHECK(instance2->CreationContext() == context2);
18559 CheckContextId(instance2, 2);
18563 Context::Scope scope(context2);
18564 CHECK(object1->CreationContext() == context1);
18565 CheckContextId(object1, 1);
18566 CHECK(func1->CreationContext() == context1);
18567 CheckContextId(func1, 1);
18568 CHECK(instance1->CreationContext() == context1);
18569 CheckContextId(instance1, 1);
18570 CHECK(object2->CreationContext() == context2);
18571 CheckContextId(object2, 2);
18572 CHECK(func2->CreationContext() == context2);
18573 CheckContextId(func2, 2);
18574 CHECK(instance2->CreationContext() == context2);
18575 CheckContextId(instance2, 2);
18580 THREADED_TEST(CreationContextOfJsFunction) {
18581 HandleScope handle_scope(v8::Isolate::GetCurrent());
18582 Handle<Context> context = Context::New(v8::Isolate::GetCurrent());
18583 InstallContextId(context, 1);
18585 Local<Object> function;
18587 Context::Scope scope(context);
18588 function = CompileRun("function foo() {}; foo").As<Object>();
18591 CHECK(function->CreationContext() == context);
18592 CheckContextId(function, 1);
18596 void HasOwnPropertyIndexedPropertyGetter(
18598 const v8::PropertyCallbackInfo<v8::Value>& info) {
18599 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
18603 void HasOwnPropertyNamedPropertyGetter(
18604 Local<String> property,
18605 const v8::PropertyCallbackInfo<v8::Value>& info) {
18606 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
18610 void HasOwnPropertyIndexedPropertyQuery(
18611 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18612 if (index == 42) info.GetReturnValue().Set(1);
18616 void HasOwnPropertyNamedPropertyQuery(
18617 Local<String> property,
18618 const v8::PropertyCallbackInfo<v8::Integer>& info) {
18619 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
18623 void HasOwnPropertyNamedPropertyQuery2(
18624 Local<String> property,
18625 const v8::PropertyCallbackInfo<v8::Integer>& info) {
18626 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
18630 void HasOwnPropertyAccessorGetter(
18631 Local<String> property,
18632 const v8::PropertyCallbackInfo<v8::Value>& info) {
18633 info.GetReturnValue().Set(v8_str("yes"));
18637 TEST(HasOwnProperty) {
18639 v8::HandleScope scope(env->GetIsolate());
18640 { // Check normal properties and defined getters.
18641 Handle<Value> value = CompileRun(
18644 " this.__defineGetter__('baz', function() { return 1; });"
18646 "function Bar() { "
18648 " this.__defineGetter__('bla', function() { return 2; });"
18650 "Bar.prototype = new Foo();"
18652 CHECK(value->IsObject());
18653 Handle<Object> object = value->ToObject();
18654 CHECK(object->Has(v8_str("foo")));
18655 CHECK(!object->HasOwnProperty(v8_str("foo")));
18656 CHECK(object->HasOwnProperty(v8_str("bar")));
18657 CHECK(object->Has(v8_str("baz")));
18658 CHECK(!object->HasOwnProperty(v8_str("baz")));
18659 CHECK(object->HasOwnProperty(v8_str("bla")));
18661 { // Check named getter interceptors.
18662 Handle<ObjectTemplate> templ = ObjectTemplate::New();
18663 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
18664 Handle<Object> instance = templ->NewInstance();
18665 CHECK(!instance->HasOwnProperty(v8_str("42")));
18666 CHECK(instance->HasOwnProperty(v8_str("foo")));
18667 CHECK(!instance->HasOwnProperty(v8_str("bar")));
18669 { // Check indexed getter interceptors.
18670 Handle<ObjectTemplate> templ = ObjectTemplate::New();
18671 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
18672 Handle<Object> instance = templ->NewInstance();
18673 CHECK(instance->HasOwnProperty(v8_str("42")));
18674 CHECK(!instance->HasOwnProperty(v8_str("43")));
18675 CHECK(!instance->HasOwnProperty(v8_str("foo")));
18677 { // Check named query interceptors.
18678 Handle<ObjectTemplate> templ = ObjectTemplate::New();
18679 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
18680 Handle<Object> instance = templ->NewInstance();
18681 CHECK(instance->HasOwnProperty(v8_str("foo")));
18682 CHECK(!instance->HasOwnProperty(v8_str("bar")));
18684 { // Check indexed query interceptors.
18685 Handle<ObjectTemplate> templ = ObjectTemplate::New();
18686 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
18687 Handle<Object> instance = templ->NewInstance();
18688 CHECK(instance->HasOwnProperty(v8_str("42")));
18689 CHECK(!instance->HasOwnProperty(v8_str("41")));
18691 { // Check callbacks.
18692 Handle<ObjectTemplate> templ = ObjectTemplate::New();
18693 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
18694 Handle<Object> instance = templ->NewInstance();
18695 CHECK(instance->HasOwnProperty(v8_str("foo")));
18696 CHECK(!instance->HasOwnProperty(v8_str("bar")));
18698 { // Check that query wins on disagreement.
18699 Handle<ObjectTemplate> templ = ObjectTemplate::New();
18700 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
18702 HasOwnPropertyNamedPropertyQuery2);
18703 Handle<Object> instance = templ->NewInstance();
18704 CHECK(!instance->HasOwnProperty(v8_str("foo")));
18705 CHECK(instance->HasOwnProperty(v8_str("bar")));
18710 TEST(IndexedInterceptorWithStringProto) {
18711 v8::HandleScope scope(v8::Isolate::GetCurrent());
18712 Handle<ObjectTemplate> templ = ObjectTemplate::New();
18713 templ->SetIndexedPropertyHandler(NULL,
18715 HasOwnPropertyIndexedPropertyQuery);
18716 LocalContext context;
18717 context->Global()->Set(v8_str("obj"), templ->NewInstance());
18718 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
18719 // These should be intercepted.
18720 CHECK(CompileRun("42 in obj")->BooleanValue());
18721 CHECK(CompileRun("'42' in obj")->BooleanValue());
18722 // These should fall through to the String prototype.
18723 CHECK(CompileRun("0 in obj")->BooleanValue());
18724 CHECK(CompileRun("'0' in obj")->BooleanValue());
18725 // And these should both fail.
18726 CHECK(!CompileRun("32 in obj")->BooleanValue());
18727 CHECK(!CompileRun("'32' in obj")->BooleanValue());
18731 void CheckCodeGenerationAllowed() {
18732 Handle<Value> result = CompileRun("eval('42')");
18733 CHECK_EQ(42, result->Int32Value());
18734 result = CompileRun("(function(e) { return e('42'); })(eval)");
18735 CHECK_EQ(42, result->Int32Value());
18736 result = CompileRun("var f = new Function('return 42'); f()");
18737 CHECK_EQ(42, result->Int32Value());
18741 void CheckCodeGenerationDisallowed() {
18742 TryCatch try_catch;
18744 Handle<Value> result = CompileRun("eval('42')");
18745 CHECK(result.IsEmpty());
18746 CHECK(try_catch.HasCaught());
18749 result = CompileRun("(function(e) { return e('42'); })(eval)");
18750 CHECK(result.IsEmpty());
18751 CHECK(try_catch.HasCaught());
18754 result = CompileRun("var f = new Function('return 42'); f()");
18755 CHECK(result.IsEmpty());
18756 CHECK(try_catch.HasCaught());
18760 bool CodeGenerationAllowed(Local<Context> context) {
18761 ApiTestFuzzer::Fuzz();
18766 bool CodeGenerationDisallowed(Local<Context> context) {
18767 ApiTestFuzzer::Fuzz();
18772 THREADED_TEST(AllowCodeGenFromStrings) {
18773 LocalContext context;
18774 v8::HandleScope scope(context->GetIsolate());
18776 // eval and the Function constructor allowed by default.
18777 CHECK(context->IsCodeGenerationFromStringsAllowed());
18778 CheckCodeGenerationAllowed();
18780 // Disallow eval and the Function constructor.
18781 context->AllowCodeGenerationFromStrings(false);
18782 CHECK(!context->IsCodeGenerationFromStringsAllowed());
18783 CheckCodeGenerationDisallowed();
18786 context->AllowCodeGenerationFromStrings(true);
18787 CheckCodeGenerationAllowed();
18789 // Disallow but setting a global callback that will allow the calls.
18790 context->AllowCodeGenerationFromStrings(false);
18791 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
18792 CHECK(!context->IsCodeGenerationFromStringsAllowed());
18793 CheckCodeGenerationAllowed();
18795 // Set a callback that disallows the code generation.
18796 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
18797 CHECK(!context->IsCodeGenerationFromStringsAllowed());
18798 CheckCodeGenerationDisallowed();
18802 TEST(SetErrorMessageForCodeGenFromStrings) {
18803 LocalContext context;
18804 v8::HandleScope scope(context->GetIsolate());
18805 TryCatch try_catch;
18807 Handle<String> message = v8_str("Message") ;
18808 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
18809 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
18810 context->AllowCodeGenerationFromStrings(false);
18811 context->SetErrorMessageForCodeGenerationFromStrings(message);
18812 Handle<Value> result = CompileRun("eval('42')");
18813 CHECK(result.IsEmpty());
18814 CHECK(try_catch.HasCaught());
18815 Handle<String> actual_message = try_catch.Message()->Get();
18816 CHECK(expected_message->Equals(actual_message));
18820 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
18824 THREADED_TEST(CallAPIFunctionOnNonObject) {
18825 LocalContext context;
18826 v8::HandleScope scope(context->GetIsolate());
18827 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis);
18828 Handle<Function> function = templ->GetFunction();
18829 context->Global()->Set(v8_str("f"), function);
18830 TryCatch try_catch;
18831 CompileRun("f.call(2)");
18835 // Regression test for issue 1470.
18836 THREADED_TEST(ReadOnlyIndexedProperties) {
18837 v8::HandleScope scope(v8::Isolate::GetCurrent());
18838 Local<ObjectTemplate> templ = ObjectTemplate::New();
18840 LocalContext context;
18841 Local<v8::Object> obj = templ->NewInstance();
18842 context->Global()->Set(v8_str("obj"), obj);
18843 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18844 obj->Set(v8_str("1"), v8_str("foobar"));
18845 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
18846 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
18847 obj->Set(v8_num(2), v8_str("foobar"));
18848 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
18850 // Test non-smi case.
18851 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18852 obj->Set(v8_str("2000000000"), v8_str("foobar"));
18853 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
18857 THREADED_TEST(Regress1516) {
18858 LocalContext context;
18859 v8::HandleScope scope(context->GetIsolate());
18861 { v8::HandleScope temp_scope(context->GetIsolate());
18862 CompileRun("({'a': 0})");
18866 { i::MapCache* map_cache =
18867 i::MapCache::cast(i::Isolate::Current()->context()->map_cache());
18868 elements = map_cache->NumberOfElements();
18869 CHECK_LE(1, elements);
18872 i::Isolate::Current()->heap()->CollectAllGarbage(
18873 i::Heap::kAbortIncrementalMarkingMask);
18874 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache();
18875 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) {
18876 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
18877 CHECK_GT(elements, map_cache->NumberOfElements());
18883 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
18885 v8::AccessType type,
18886 Local<Value> data) {
18887 // Only block read access to __proto__.
18888 if (type == v8::ACCESS_GET &&
18889 name->IsString() &&
18890 name->ToString()->Length() == 9 &&
18891 name->ToString()->Utf8Length() == 9) {
18893 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
18894 return strncmp(buffer, "__proto__", 9) != 0;
18901 THREADED_TEST(Regress93759) {
18902 v8::Isolate* isolate = v8::Isolate::GetCurrent();
18903 HandleScope scope(isolate);
18905 // Template for object with security check.
18906 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New();
18907 // We don't do indexing, so any callback can be used for that.
18908 no_proto_template->SetAccessCheckCallbacks(
18909 BlockProtoNamedSecurityTestCallback,
18910 IndexedSecurityTestCallback);
18912 // Templates for objects with hidden prototypes and possibly security check.
18913 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New();
18914 hidden_proto_template->SetHiddenPrototype(true);
18916 Local<FunctionTemplate> protected_hidden_proto_template =
18917 v8::FunctionTemplate::New();
18918 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
18919 BlockProtoNamedSecurityTestCallback,
18920 IndexedSecurityTestCallback);
18921 protected_hidden_proto_template->SetHiddenPrototype(true);
18923 // Context for "foreign" objects used in test.
18924 Local<Context> context = v8::Context::New(isolate);
18927 // Plain object, no security check.
18928 Local<Object> simple_object = Object::New();
18930 // Object with explicit security check.
18931 Local<Object> protected_object =
18932 no_proto_template->NewInstance();
18934 // JSGlobalProxy object, always have security check.
18935 Local<Object> proxy_object =
18938 // Global object, the prototype of proxy_object. No security checks.
18939 Local<Object> global_object =
18940 proxy_object->GetPrototype()->ToObject();
18942 // Hidden prototype without security check.
18943 Local<Object> hidden_prototype =
18944 hidden_proto_template->GetFunction()->NewInstance();
18945 Local<Object> object_with_hidden =
18947 object_with_hidden->SetPrototype(hidden_prototype);
18949 // Hidden prototype with security check on the hidden prototype.
18950 Local<Object> protected_hidden_prototype =
18951 protected_hidden_proto_template->GetFunction()->NewInstance();
18952 Local<Object> object_with_protected_hidden =
18954 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
18958 // Template for object for second context. Values to test are put on it as
18960 Local<ObjectTemplate> global_template = ObjectTemplate::New();
18961 global_template->Set(v8_str("simple"), simple_object);
18962 global_template->Set(v8_str("protected"), protected_object);
18963 global_template->Set(v8_str("global"), global_object);
18964 global_template->Set(v8_str("proxy"), proxy_object);
18965 global_template->Set(v8_str("hidden"), object_with_hidden);
18966 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
18968 LocalContext context2(NULL, global_template);
18970 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
18971 CHECK(result1->Equals(simple_object->GetPrototype()));
18973 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
18974 CHECK(result2->Equals(Undefined()));
18976 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
18977 CHECK(result3->Equals(global_object->GetPrototype()));
18979 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
18980 CHECK(result4->Equals(Undefined()));
18982 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
18983 CHECK(result5->Equals(
18984 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
18986 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
18987 CHECK(result6->Equals(Undefined()));
18991 THREADED_TEST(Regress125988) {
18992 v8::HandleScope scope(v8::Isolate::GetCurrent());
18993 Handle<FunctionTemplate> intercept = FunctionTemplate::New();
18994 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
18996 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
18997 CompileRun("var a = new Object();"
18998 "var b = new Intercept();"
18999 "var c = new Object();"
19003 "for (var i = 0; i < 3; i++) c.x;");
19004 ExpectBoolean("c.hasOwnProperty('x')", false);
19005 ExpectInt32("c.x", 23);
19006 CompileRun("a.y = 42;"
19007 "for (var i = 0; i < 3; i++) c.x;");
19008 ExpectBoolean("c.hasOwnProperty('x')", false);
19009 ExpectInt32("c.x", 23);
19010 ExpectBoolean("c.hasOwnProperty('y')", false);
19011 ExpectInt32("c.y", 42);
19015 static void TestReceiver(Local<Value> expected_result,
19016 Local<Value> expected_receiver,
19017 const char* code) {
19018 Local<Value> result = CompileRun(code);
19019 CHECK(result->IsObject());
19020 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
19021 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
19025 THREADED_TEST(ForeignFunctionReceiver) {
19026 v8::Isolate* isolate = v8::Isolate::GetCurrent();
19027 HandleScope scope(isolate);
19029 // Create two contexts with different "id" properties ('i' and 'o').
19030 // Call a function both from its own context and from a the foreign
19031 // context, and see what "this" is bound to (returning both "this"
19032 // and "this.id" for comparison).
19034 Local<Context> foreign_context = v8::Context::New(isolate);
19035 foreign_context->Enter();
19036 Local<Value> foreign_function =
19037 CompileRun("function func() { return { 0: this.id, "
19039 " toString: function() { "
19046 CHECK(foreign_function->IsFunction());
19047 foreign_context->Exit();
19049 LocalContext context;
19051 Local<String> password = v8_str("Password");
19052 // Don't get hit by security checks when accessing foreign_context's
19053 // global receiver (aka. global proxy).
19054 context->SetSecurityToken(password);
19055 foreign_context->SetSecurityToken(password);
19057 Local<String> i = v8_str("i");
19058 Local<String> o = v8_str("o");
19059 Local<String> id = v8_str("id");
19061 CompileRun("function ownfunc() { return { 0: this.id, "
19063 " toString: function() { "
19070 context->Global()->Set(v8_str("func"), foreign_function);
19072 // Sanity check the contexts.
19073 CHECK(i->Equals(foreign_context->Global()->Get(id)));
19074 CHECK(o->Equals(context->Global()->Get(id)));
19076 // Checking local function's receiver.
19077 // Calling function using its call/apply methods.
19078 TestReceiver(o, context->Global(), "ownfunc.call()");
19079 TestReceiver(o, context->Global(), "ownfunc.apply()");
19080 // Making calls through built-in functions.
19081 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
19082 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
19083 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
19084 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
19085 // Calling with environment record as base.
19086 TestReceiver(o, context->Global(), "ownfunc()");
19087 // Calling with no base.
19088 TestReceiver(o, context->Global(), "(1,ownfunc)()");
19090 // Checking foreign function return value.
19091 // Calling function using its call/apply methods.
19092 TestReceiver(i, foreign_context->Global(), "func.call()");
19093 TestReceiver(i, foreign_context->Global(), "func.apply()");
19094 // Calling function using another context's call/apply methods.
19095 TestReceiver(i, foreign_context->Global(),
19096 "Function.prototype.call.call(func)");
19097 TestReceiver(i, foreign_context->Global(),
19098 "Function.prototype.call.apply(func)");
19099 TestReceiver(i, foreign_context->Global(),
19100 "Function.prototype.apply.call(func)");
19101 TestReceiver(i, foreign_context->Global(),
19102 "Function.prototype.apply.apply(func)");
19103 // Making calls through built-in functions.
19104 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
19105 // ToString(func()) is func()[0], i.e., the returned this.id.
19106 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
19107 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
19108 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
19110 // TODO(1547): Make the following also return "i".
19111 // Calling with environment record as base.
19112 TestReceiver(o, context->Global(), "func()");
19113 // Calling with no base.
19114 TestReceiver(o, context->Global(), "(1,func)()");
19118 uint8_t callback_fired = 0;
19121 void CallCompletedCallback1() {
19122 i::OS::Print("Firing callback 1.\n");
19123 callback_fired ^= 1; // Toggle first bit.
19127 void CallCompletedCallback2() {
19128 i::OS::Print("Firing callback 2.\n");
19129 callback_fired ^= 2; // Toggle second bit.
19133 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
19134 int32_t level = args[0]->Int32Value();
19137 i::OS::Print("Entering recursion level %d.\n", level);
19139 i::Vector<char> script_vector(script, sizeof(script));
19140 i::OS::SNPrintF(script_vector, "recursion(%d)", level);
19141 CompileRun(script_vector.start());
19142 i::OS::Print("Leaving recursion level %d.\n", level);
19143 CHECK_EQ(0, callback_fired);
19145 i::OS::Print("Recursion ends.\n");
19146 CHECK_EQ(0, callback_fired);
19151 TEST(CallCompletedCallback) {
19153 v8::HandleScope scope(env->GetIsolate());
19154 v8::Handle<v8::FunctionTemplate> recursive_runtime =
19155 v8::FunctionTemplate::New(RecursiveCall);
19156 env->Global()->Set(v8_str("recursion"),
19157 recursive_runtime->GetFunction());
19158 // Adding the same callback a second time has no effect.
19159 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
19160 v8::V8::AddCallCompletedCallback(CallCompletedCallback1);
19161 v8::V8::AddCallCompletedCallback(CallCompletedCallback2);
19162 i::OS::Print("--- Script (1) ---\n");
19163 Local<Script> script =
19164 v8::Script::Compile(v8::String::New("recursion(0)"));
19166 CHECK_EQ(3, callback_fired);
19168 i::OS::Print("\n--- Script (2) ---\n");
19169 callback_fired = 0;
19170 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1);
19172 CHECK_EQ(2, callback_fired);
19174 i::OS::Print("\n--- Function ---\n");
19175 callback_fired = 0;
19176 Local<Function> recursive_function =
19177 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
19178 v8::Handle<Value> args[] = { v8_num(0) };
19179 recursive_function->Call(env->Global(), 1, args);
19180 CHECK_EQ(2, callback_fired);
19184 void CallCompletedCallbackNoException() {
19185 v8::HandleScope scope(v8::Isolate::GetCurrent());
19186 CompileRun("1+1;");
19190 void CallCompletedCallbackException() {
19191 v8::HandleScope scope(v8::Isolate::GetCurrent());
19192 CompileRun("throw 'second exception';");
19196 TEST(CallCompletedCallbackOneException) {
19198 v8::HandleScope scope(env->GetIsolate());
19199 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException);
19200 CompileRun("throw 'exception';");
19204 TEST(CallCompletedCallbackTwoExceptions) {
19206 v8::HandleScope scope(env->GetIsolate());
19207 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException);
19208 CompileRun("throw 'first exception';");
19212 static int probes_counter = 0;
19213 static int misses_counter = 0;
19214 static int updates_counter = 0;
19217 static int* LookupCounter(const char* name) {
19218 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
19219 return &probes_counter;
19220 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
19221 return &misses_counter;
19222 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
19223 return &updates_counter;
19229 static const char* kMegamorphicTestProgram =
19230 "function ClassA() { };"
19231 "function ClassB() { };"
19232 "ClassA.prototype.foo = function() { };"
19233 "ClassB.prototype.foo = function() { };"
19234 "function fooify(obj) { obj.foo(); };"
19235 "var a = new ClassA();"
19236 "var b = new ClassB();"
19237 "for (var i = 0; i < 10000; i++) {"
19243 static void StubCacheHelper(bool primary) {
19244 V8::SetCounterFunction(LookupCounter);
19245 USE(kMegamorphicTestProgram);
19247 i::FLAG_native_code_counters = true;
19249 i::FLAG_test_primary_stub_cache = true;
19251 i::FLAG_test_secondary_stub_cache = true;
19253 i::FLAG_crankshaft = false;
19255 v8::HandleScope scope(env->GetIsolate());
19256 int initial_probes = probes_counter;
19257 int initial_misses = misses_counter;
19258 int initial_updates = updates_counter;
19259 CompileRun(kMegamorphicTestProgram);
19260 int probes = probes_counter - initial_probes;
19261 int misses = misses_counter - initial_misses;
19262 int updates = updates_counter - initial_updates;
19263 CHECK_LT(updates, 10);
19264 CHECK_LT(misses, 10);
19265 CHECK_GE(probes, 10000);
19270 TEST(SecondaryStubCache) {
19271 StubCacheHelper(true);
19275 TEST(PrimaryStubCache) {
19276 StubCacheHelper(false);
19280 TEST(StaticGetters) {
19281 LocalContext context;
19282 i::Factory* factory = i::Isolate::Current()->factory();
19283 v8::Isolate* isolate = v8::Isolate::GetCurrent();
19284 v8::HandleScope scope(isolate);
19285 i::Handle<i::Object> undefined_value = factory->undefined_value();
19286 CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value);
19287 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
19288 i::Handle<i::Object> null_value = factory->null_value();
19289 CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value);
19290 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
19291 i::Handle<i::Object> true_value = factory->true_value();
19292 CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value);
19293 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
19294 i::Handle<i::Object> false_value = factory->false_value();
19295 CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value);
19296 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
19300 TEST(IsolateEmbedderData) {
19301 v8::Isolate* isolate = v8::Isolate::GetCurrent();
19302 CHECK_EQ(NULL, isolate->GetData());
19303 CHECK_EQ(NULL, ISOLATE->GetData());
19304 static void* data1 = reinterpret_cast<void*>(0xacce55ed);
19305 isolate->SetData(data1);
19306 CHECK_EQ(data1, isolate->GetData());
19307 CHECK_EQ(data1, ISOLATE->GetData());
19308 static void* data2 = reinterpret_cast<void*>(0xdecea5ed);
19309 ISOLATE->SetData(data2);
19310 CHECK_EQ(data2, isolate->GetData());
19311 CHECK_EQ(data2, ISOLATE->GetData());
19312 ISOLATE->TearDown();
19313 CHECK_EQ(data2, isolate->GetData());
19314 CHECK_EQ(data2, ISOLATE->GetData());
19318 TEST(StringEmpty) {
19319 LocalContext context;
19320 i::Factory* factory = i::Isolate::Current()->factory();
19321 v8::Isolate* isolate = v8::Isolate::GetCurrent();
19322 v8::HandleScope scope(isolate);
19323 i::Handle<i::Object> empty_string = factory->empty_string();
19324 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string);
19325 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
19329 static int instance_checked_getter_count = 0;
19330 static void InstanceCheckedGetter(
19331 Local<String> name,
19332 const v8::PropertyCallbackInfo<v8::Value>& info) {
19333 CHECK_EQ(name, v8_str("foo"));
19334 instance_checked_getter_count++;
19335 info.GetReturnValue().Set(v8_num(11));
19339 static int instance_checked_setter_count = 0;
19340 static void InstanceCheckedSetter(Local<String> name,
19341 Local<Value> value,
19342 const v8::PropertyCallbackInfo<void>& info) {
19343 CHECK_EQ(name, v8_str("foo"));
19344 CHECK_EQ(value, v8_num(23));
19345 instance_checked_setter_count++;
19349 static void CheckInstanceCheckedResult(int getters,
19351 bool expects_callbacks,
19352 TryCatch* try_catch) {
19353 if (expects_callbacks) {
19354 CHECK(!try_catch->HasCaught());
19355 CHECK_EQ(getters, instance_checked_getter_count);
19356 CHECK_EQ(setters, instance_checked_setter_count);
19358 CHECK(try_catch->HasCaught());
19359 CHECK_EQ(0, instance_checked_getter_count);
19360 CHECK_EQ(0, instance_checked_setter_count);
19362 try_catch->Reset();
19366 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
19367 instance_checked_getter_count = 0;
19368 instance_checked_setter_count = 0;
19369 TryCatch try_catch;
19371 // Test path through generic runtime code.
19372 CompileRun("obj.foo");
19373 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
19374 CompileRun("obj.foo = 23");
19375 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
19377 // Test path through generated LoadIC and StoredIC.
19378 CompileRun("function test_get(o) { o.foo; }"
19380 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
19381 CompileRun("test_get(obj);");
19382 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
19383 CompileRun("test_get(obj);");
19384 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
19385 CompileRun("function test_set(o) { o.foo = 23; }"
19387 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
19388 CompileRun("test_set(obj);");
19389 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
19390 CompileRun("test_set(obj);");
19391 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
19393 // Test path through optimized code.
19394 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
19396 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
19397 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
19399 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
19401 // Cleanup so that closures start out fresh in next check.
19402 CompileRun("%DeoptimizeFunction(test_get);"
19403 "%ClearFunctionTypeFeedback(test_get);"
19404 "%DeoptimizeFunction(test_set);"
19405 "%ClearFunctionTypeFeedback(test_set);");
19409 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
19410 v8::internal::FLAG_allow_natives_syntax = true;
19411 LocalContext context;
19412 v8::HandleScope scope(context->GetIsolate());
19414 Local<FunctionTemplate> templ = FunctionTemplate::New();
19415 Local<ObjectTemplate> inst = templ->InstanceTemplate();
19416 inst->SetAccessor(v8_str("foo"),
19417 InstanceCheckedGetter, InstanceCheckedSetter,
19421 v8::AccessorSignature::New(templ));
19422 context->Global()->Set(v8_str("f"), templ->GetFunction());
19424 printf("Testing positive ...\n");
19425 CompileRun("var obj = new f();");
19426 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19427 CheckInstanceCheckedAccessors(true);
19429 printf("Testing negative ...\n");
19430 CompileRun("var obj = {};"
19431 "obj.__proto__ = new f();");
19432 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19433 CheckInstanceCheckedAccessors(false);
19437 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
19438 v8::internal::FLAG_allow_natives_syntax = true;
19439 LocalContext context;
19440 v8::HandleScope scope(context->GetIsolate());
19442 Local<FunctionTemplate> templ = FunctionTemplate::New();
19443 Local<ObjectTemplate> inst = templ->InstanceTemplate();
19444 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
19445 inst->SetAccessor(v8_str("foo"),
19446 InstanceCheckedGetter, InstanceCheckedSetter,
19450 v8::AccessorSignature::New(templ));
19451 context->Global()->Set(v8_str("f"), templ->GetFunction());
19453 printf("Testing positive ...\n");
19454 CompileRun("var obj = new f();");
19455 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19456 CheckInstanceCheckedAccessors(true);
19458 printf("Testing negative ...\n");
19459 CompileRun("var obj = {};"
19460 "obj.__proto__ = new f();");
19461 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19462 CheckInstanceCheckedAccessors(false);
19466 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
19467 v8::internal::FLAG_allow_natives_syntax = true;
19468 LocalContext context;
19469 v8::HandleScope scope(context->GetIsolate());
19471 Local<FunctionTemplate> templ = FunctionTemplate::New();
19472 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
19473 proto->SetAccessor(v8_str("foo"),
19474 InstanceCheckedGetter, InstanceCheckedSetter,
19478 v8::AccessorSignature::New(templ));
19479 context->Global()->Set(v8_str("f"), templ->GetFunction());
19481 printf("Testing positive ...\n");
19482 CompileRun("var obj = new f();");
19483 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19484 CheckInstanceCheckedAccessors(true);
19486 printf("Testing negative ...\n");
19487 CompileRun("var obj = {};"
19488 "obj.__proto__ = new f();");
19489 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19490 CheckInstanceCheckedAccessors(false);
19492 printf("Testing positive with modified prototype chain ...\n");
19493 CompileRun("var obj = new f();"
19495 "pro.__proto__ = obj.__proto__;"
19496 "obj.__proto__ = pro;");
19497 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19498 CheckInstanceCheckedAccessors(true);
19502 TEST(TryFinallyMessage) {
19503 LocalContext context;
19504 v8::HandleScope scope(context->GetIsolate());
19506 // Test that the original error message is not lost if there is a
19507 // recursive call into Javascript is done in the finally block, e.g. to
19508 // initialize an IC. (crbug.com/129171)
19509 TryCatch try_catch;
19510 const char* trigger_ic =
19512 " throw new Error('test'); \n"
19515 " x++; \n" // Trigger an IC initialization here.
19517 CompileRun(trigger_ic);
19518 CHECK(try_catch.HasCaught());
19519 Local<Message> message = try_catch.Message();
19520 CHECK(!message.IsEmpty());
19521 CHECK_EQ(2, message->GetLineNumber());
19525 // Test that the original exception message is indeed overwritten if
19526 // a new error is thrown in the finally block.
19527 TryCatch try_catch;
19528 const char* throw_again =
19530 " throw new Error('test'); \n"
19534 " throw new Error('again'); \n" // This is the new uncaught error.
19536 CompileRun(throw_again);
19537 CHECK(try_catch.HasCaught());
19538 Local<Message> message = try_catch.Message();
19539 CHECK(!message.IsEmpty());
19540 CHECK_EQ(6, message->GetLineNumber());
19545 static void Helper137002(bool do_store,
19547 bool remove_accessor,
19548 bool interceptor) {
19549 LocalContext context;
19550 Local<ObjectTemplate> templ = ObjectTemplate::New();
19552 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
19554 templ->SetAccessor(v8_str("foo"),
19555 GetterWhichReturns42,
19556 SetterWhichSetsYOnThisTo23);
19558 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19560 // Turn monomorphic on slow object with native accessor, then turn
19561 // polymorphic, finally optimize to create negative lookup and fail.
19562 CompileRun(do_store ?
19563 "function f(x) { x.foo = void 0; }" :
19564 "function f(x) { return x.foo; }");
19565 CompileRun("obj.y = void 0;");
19566 if (!interceptor) {
19567 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
19569 CompileRun("obj.__proto__ = null;"
19570 "f(obj); f(obj); f(obj);");
19572 CompileRun("f({});");
19574 CompileRun("obj.y = void 0;"
19575 "%OptimizeFunctionOnNextCall(f);");
19576 if (remove_accessor) {
19577 CompileRun("delete obj.foo;");
19579 CompileRun("var result = f(obj);");
19581 CompileRun("result = obj.y;");
19583 if (remove_accessor && !interceptor) {
19584 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
19586 CHECK_EQ(do_store ? 23 : 42,
19587 context->Global()->Get(v8_str("result"))->Int32Value());
19592 THREADED_TEST(Regress137002a) {
19593 i::FLAG_allow_natives_syntax = true;
19594 i::FLAG_compilation_cache = false;
19595 v8::HandleScope scope(v8::Isolate::GetCurrent());
19596 for (int i = 0; i < 16; i++) {
19597 Helper137002(i & 8, i & 4, i & 2, i & 1);
19602 THREADED_TEST(Regress137002b) {
19603 i::FLAG_allow_natives_syntax = true;
19604 LocalContext context;
19605 v8::HandleScope scope(context->GetIsolate());
19606 Local<ObjectTemplate> templ = ObjectTemplate::New();
19607 templ->SetAccessor(v8_str("foo"),
19608 GetterWhichReturns42,
19609 SetterWhichSetsYOnThisTo23);
19610 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19612 // Turn monomorphic on slow object with native accessor, then just
19613 // delete the property and fail.
19614 CompileRun("function load(x) { return x.foo; }"
19615 "function store(x) { x.foo = void 0; }"
19616 "function keyed_load(x, key) { return x[key]; }"
19617 // Second version of function has a different source (add void 0)
19618 // so that it does not share code with the first version. This
19619 // ensures that the ICs are monomorphic.
19620 "function load2(x) { void 0; return x.foo; }"
19621 "function store2(x) { void 0; x.foo = void 0; }"
19622 "function keyed_load2(x, key) { void 0; return x[key]; }"
19625 "obj.__proto__ = null;"
19627 "subobj.y = void 0;"
19628 "subobj.__proto__ = obj;"
19629 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19631 // Make the ICs monomorphic.
19632 "load(obj); load(obj);"
19633 "load2(subobj); load2(subobj);"
19634 "store(obj); store(obj);"
19635 "store2(subobj); store2(subobj);"
19636 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
19637 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
19639 // Actually test the shiny new ICs and better not crash. This
19640 // serves as a regression test for issue 142088 as well.
19645 "keyed_load(obj, 'foo');"
19646 "keyed_load2(subobj, 'foo');"
19648 // Delete the accessor. It better not be called any more now.
19651 "subobj.y = void 0;"
19653 "var load_result = load(obj);"
19654 "var load_result2 = load2(subobj);"
19655 "var keyed_load_result = keyed_load(obj, 'foo');"
19656 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
19659 "var y_from_obj = obj.y;"
19660 "var y_from_subobj = subobj.y;");
19661 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
19662 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
19663 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
19664 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
19665 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
19666 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
19670 THREADED_TEST(Regress142088) {
19671 i::FLAG_allow_natives_syntax = true;
19672 LocalContext context;
19673 v8::HandleScope scope(context->GetIsolate());
19674 Local<ObjectTemplate> templ = ObjectTemplate::New();
19675 templ->SetAccessor(v8_str("foo"),
19676 GetterWhichReturns42,
19677 SetterWhichSetsYOnThisTo23);
19678 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19680 CompileRun("function load(x) { return x.foo; }"
19681 "var o = Object.create(obj);"
19682 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19683 "load(o); load(o); load(o); load(o);");
19687 THREADED_TEST(Regress137496) {
19688 i::FLAG_expose_gc = true;
19689 LocalContext context;
19690 v8::HandleScope scope(context->GetIsolate());
19692 // Compile a try-finally clause where the finally block causes a GC
19693 // while there still is a message pending for external reporting.
19694 TryCatch try_catch;
19695 try_catch.SetVerbose(true);
19696 CompileRun("try { throw new Error(); } finally { gc(); }");
19697 CHECK(try_catch.HasCaught());
19701 THREADED_TEST(Regress149912) {
19702 LocalContext context;
19703 v8::HandleScope scope(context->GetIsolate());
19704 Handle<FunctionTemplate> templ = FunctionTemplate::New();
19705 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
19706 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
19707 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
19711 THREADED_TEST(Regress157124) {
19712 LocalContext context;
19713 v8::HandleScope scope(context->GetIsolate());
19714 Local<ObjectTemplate> templ = ObjectTemplate::New();
19715 Local<Object> obj = templ->NewInstance();
19716 obj->GetIdentityHash();
19717 obj->DeleteHiddenValue(v8_str("Bug"));
19721 THREADED_TEST(Regress2535) {
19722 i::FLAG_harmony_collections = true;
19723 LocalContext context;
19724 v8::HandleScope scope(context->GetIsolate());
19725 Local<Value> set_value = CompileRun("new Set();");
19726 Local<Object> set_object(Local<Object>::Cast(set_value));
19727 CHECK_EQ(0, set_object->InternalFieldCount());
19728 Local<Value> map_value = CompileRun("new Map();");
19729 Local<Object> map_object(Local<Object>::Cast(map_value));
19730 CHECK_EQ(0, map_object->InternalFieldCount());
19734 THREADED_TEST(Regress2746) {
19735 LocalContext context;
19736 v8::HandleScope scope(context->GetIsolate());
19737 Local<Object> obj = Object::New();
19738 Local<String> key = String::New("key");
19739 obj->SetHiddenValue(key, v8::Undefined());
19740 Local<Value> value = obj->GetHiddenValue(key);
19741 CHECK(!value.IsEmpty());
19742 CHECK(value->IsUndefined());
19746 THREADED_TEST(Regress260106) {
19747 LocalContext context;
19748 v8::HandleScope scope(context->GetIsolate());
19749 Local<FunctionTemplate> templ = FunctionTemplate::New(DummyCallHandler);
19750 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
19751 Local<Function> function = templ->GetFunction();
19752 CHECK(!function.IsEmpty());
19753 CHECK(function->IsFunction());
19758 class ThreadInterruptTest {
19760 ThreadInterruptTest() : sem_(NULL), sem_value_(0) { }
19761 ~ThreadInterruptTest() { delete sem_; }
19764 sem_ = i::OS::CreateSemaphore(0);
19766 InterruptThread i_thread(this);
19770 CHECK_EQ(kExpectedValue, sem_value_);
19774 static const int kExpectedValue = 1;
19776 class InterruptThread : public i::Thread {
19778 explicit InterruptThread(ThreadInterruptTest* test)
19779 : Thread("InterruptThread"), test_(test) {}
19781 virtual void Run() {
19782 struct sigaction action;
19784 // Ensure that we'll enter waiting condition
19787 // Setup signal handler
19788 memset(&action, 0, sizeof(action));
19789 action.sa_handler = SignalHandler;
19790 sigaction(SIGCHLD, &action, NULL);
19793 kill(getpid(), SIGCHLD);
19795 // Ensure that if wait has returned because of error
19798 // Set value and signal semaphore
19799 test_->sem_value_ = 1;
19800 test_->sem_->Signal();
19803 static void SignalHandler(int signal) {
19807 ThreadInterruptTest* test_;
19810 i::Semaphore* sem_;
19811 volatile int sem_value_;
19815 THREADED_TEST(SemaphoreInterruption) {
19816 ThreadInterruptTest().RunTest();
19820 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
19822 v8::AccessType type,
19823 Local<Value> data) {
19824 i::PrintF("Named access blocked.\n");
19829 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
19831 v8::AccessType type,
19832 Local<Value> data) {
19833 i::PrintF("Indexed access blocked.\n");
19838 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19843 TEST(JSONStringifyAccessCheck) {
19844 v8::V8::Initialize();
19845 v8::HandleScope scope(v8::Isolate::GetCurrent());
19847 // Create an ObjectTemplate for global objects and install access
19848 // check callbacks that will block access.
19849 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
19850 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
19851 IndexAccessAlwaysBlocked);
19853 // Create a context and set an x property on it's global object.
19854 LocalContext context0(NULL, global_template);
19855 v8::Handle<v8::Object> global0 = context0->Global();
19856 global0->Set(v8_str("x"), v8_num(42));
19857 ExpectString("JSON.stringify(this)", "{\"x\":42}");
19859 for (int i = 0; i < 2; i++) {
19861 // Install a toJSON function on the second run.
19862 v8::Handle<v8::FunctionTemplate> toJSON =
19863 v8::FunctionTemplate::New(UnreachableCallback);
19865 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
19867 // Create a context with a different security token so that the
19868 // failed access check callback will be called on each access.
19869 LocalContext context1(NULL, global_template);
19870 context1->Global()->Set(v8_str("other"), global0);
19872 ExpectString("JSON.stringify(other)", "{}");
19873 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })",
19874 "{\"a\":{},\"b\":[\"c\"]}");
19875 ExpectString("JSON.stringify([other, 'b', 'c'])",
19876 "[{},\"b\",\"c\"]");
19878 v8::Handle<v8::Array> array = v8::Array::New(2);
19879 array->Set(0, v8_str("a"));
19880 array->Set(1, v8_str("b"));
19881 context1->Global()->Set(v8_str("array"), array);
19882 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
19883 array->TurnOnAccessCheck();
19884 ExpectString("JSON.stringify(array)", "[]");
19885 ExpectString("JSON.stringify([array])", "[[]]");
19886 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}");
19891 bool access_check_fail_thrown = false;
19892 bool catch_callback_called = false;
19895 // Failed access check callback that performs a GC on each invocation.
19896 void FailedAccessCheckThrows(Local<v8::Object> target,
19897 v8::AccessType type,
19898 Local<v8::Value> data) {
19899 access_check_fail_thrown = true;
19900 i::PrintF("Access check failed. Error thrown.\n");
19901 v8::ThrowException(v8::Exception::Error(v8_str("cross context")));
19905 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19906 for (int i = 0; i < args.Length(); i++) {
19907 i::PrintF("%s\n", *String::Utf8Value(args[i]));
19909 catch_callback_called = true;
19913 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19914 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
19918 void CheckCorrectThrow(const char* script) {
19919 // Test that the script, when wrapped into a try-catch, triggers the catch
19920 // clause due to failed access check throwing an exception.
19921 // The subsequent try-catch should run without any exception.
19922 access_check_fail_thrown = false;
19923 catch_callback_called = false;
19924 i::ScopedVector<char> source(1024);
19925 i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
19926 CompileRun(source.start());
19927 CHECK(access_check_fail_thrown);
19928 CHECK(catch_callback_called);
19930 access_check_fail_thrown = false;
19931 catch_callback_called = false;
19932 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
19933 CHECK(!access_check_fail_thrown);
19934 CHECK(!catch_callback_called);
19938 TEST(AccessCheckThrows) {
19939 i::FLAG_allow_natives_syntax = true;
19940 v8::V8::Initialize();
19941 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
19942 v8::HandleScope scope(v8::Isolate::GetCurrent());
19944 // Create an ObjectTemplate for global objects and install access
19945 // check callbacks that will block access.
19946 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
19947 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
19948 IndexAccessAlwaysBlocked);
19950 // Create a context and set an x property on it's global object.
19951 LocalContext context0(NULL, global_template);
19952 context0->Global()->Set(v8_str("x"), v8_num(42));
19953 v8::Handle<v8::Object> global0 = context0->Global();
19955 // Create a context with a different security token so that the
19956 // failed access check callback will be called on each access.
19957 LocalContext context1(NULL, global_template);
19958 context1->Global()->Set(v8_str("other"), global0);
19960 v8::Handle<v8::FunctionTemplate> catcher_fun =
19961 v8::FunctionTemplate::New(CatcherCallback);
19962 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
19964 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
19965 v8::FunctionTemplate::New(HasOwnPropertyCallback);
19966 context1->Global()->Set(v8_str("has_own_property"),
19967 has_own_property_fun->GetFunction());
19969 { v8::TryCatch try_catch;
19970 access_check_fail_thrown = false;
19971 CompileRun("other.x;");
19972 CHECK(access_check_fail_thrown);
19973 CHECK(try_catch.HasCaught());
19976 CheckCorrectThrow("other.x");
19977 CheckCorrectThrow("other[1]");
19978 CheckCorrectThrow("JSON.stringify(other)");
19979 CheckCorrectThrow("has_own_property(other, 'x')");
19980 CheckCorrectThrow("%GetProperty(other, 'x')");
19981 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)");
19982 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')");
19983 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
19984 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
19985 CheckCorrectThrow("%HasLocalProperty(other, 'x')");
19986 CheckCorrectThrow("%HasProperty(other, 'x')");
19987 CheckCorrectThrow("%HasElement(other, 1)");
19988 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
19989 CheckCorrectThrow("%GetPropertyNames(other)");
19990 CheckCorrectThrow("%GetLocalPropertyNames(other, true)");
19991 CheckCorrectThrow("%DefineOrRedefineAccessorProperty("
19992 "other, 'x', null, null, 1)");