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.
33 #include "test/cctest/test-api.h"
36 #include <unistd.h> // NOLINT
39 #include "include/v8-util.h"
41 #include "src/arguments.h"
42 #include "src/base/platform/platform.h"
43 #include "src/compilation-cache.h"
44 #include "src/debug.h"
45 #include "src/execution.h"
46 #include "src/objects.h"
47 #include "src/parser.h"
48 #include "src/smart-pointers.h"
49 #include "src/unicode-inl.h"
50 #include "src/utils.h"
51 #include "src/vm-state.h"
53 static const bool kLogThreading = false;
56 using ::v8::BooleanObject;
58 using ::v8::Extension;
60 using ::v8::FunctionTemplate;
62 using ::v8::HandleScope;
66 using ::v8::MessageCallback;
70 using ::v8::ObjectTemplate;
71 using ::v8::Persistent;
72 using ::v8::PropertyAttribute;
74 using ::v8::StackTrace;
78 using ::v8::Undefined;
84 #define THREADED_PROFILED_TEST(Name) \
85 static void Test##Name(); \
86 TEST(Name##WithProfiler) { \
87 RunWithProfiler(&Test##Name); \
92 void RunWithProfiler(void (*test)()) {
94 v8::HandleScope scope(env->GetIsolate());
95 v8::Local<v8::String> profile_name =
96 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
97 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
99 cpu_profiler->StartProfiling(profile_name);
101 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
105 static int signature_callback_count;
106 static Local<Value> signature_expected_receiver;
107 static void IncrementingSignatureCallback(
108 const v8::FunctionCallbackInfo<v8::Value>& args) {
109 ApiTestFuzzer::Fuzz();
110 signature_callback_count++;
111 CHECK(signature_expected_receiver->Equals(args.Holder()));
112 CHECK(signature_expected_receiver->Equals(args.This()));
113 v8::Handle<v8::Array> result =
114 v8::Array::New(args.GetIsolate(), args.Length());
115 for (int i = 0; i < args.Length(); i++)
116 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
117 args.GetReturnValue().Set(result);
121 static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
122 info.GetReturnValue().Set(42);
126 // Tests that call v8::V8::Dispose() cannot be threaded.
127 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
128 CHECK(v8::V8::Initialize());
129 CHECK(v8::V8::Dispose());
133 // Tests that call v8::V8::Dispose() cannot be threaded.
134 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
135 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
136 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
137 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
138 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
139 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
143 THREADED_TEST(Handles) {
144 v8::HandleScope scope(CcTest::isolate());
145 Local<Context> local_env;
148 local_env = env.local();
151 // Local context should still be live.
152 CHECK(!local_env.IsEmpty());
155 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
156 CHECK(!undef.IsEmpty());
157 CHECK(undef->IsUndefined());
159 const char* source = "1 + 2 + 3";
160 Local<Script> script = v8_compile(source);
161 CHECK_EQ(6, script->Run()->Int32Value());
167 THREADED_TEST(IsolateOfContext) {
168 v8::HandleScope scope(CcTest::isolate());
169 v8::Handle<Context> env = Context::New(CcTest::isolate());
171 CHECK(!env->GetIsolate()->InContext());
172 CHECK(env->GetIsolate() == CcTest::isolate());
174 CHECK(env->GetIsolate()->InContext());
175 CHECK(env->GetIsolate() == CcTest::isolate());
177 CHECK(!env->GetIsolate()->InContext());
178 CHECK(env->GetIsolate() == CcTest::isolate());
182 static void TestSignature(const char* loop_js, Local<Value> receiver,
183 v8::Isolate* isolate) {
184 i::ScopedVector<char> source(200);
186 "for (var i = 0; i < 10; i++) {"
190 signature_callback_count = 0;
191 signature_expected_receiver = receiver;
192 bool expected_to_throw = receiver.IsEmpty();
193 v8::TryCatch try_catch(isolate);
194 CompileRun(source.start());
195 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
196 if (!expected_to_throw) {
197 CHECK_EQ(10, signature_callback_count);
199 CHECK(v8_str("TypeError: Illegal invocation")
200 ->Equals(try_catch.Exception()->ToString(isolate)));
205 THREADED_TEST(ReceiverSignature) {
207 v8::Isolate* isolate = env->GetIsolate();
208 v8::HandleScope scope(isolate);
210 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
211 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
212 v8::Handle<v8::FunctionTemplate> callback_sig =
213 v8::FunctionTemplate::New(
214 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
215 v8::Handle<v8::FunctionTemplate> callback =
216 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
217 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
218 sub_fun->Inherit(fun);
219 v8::Handle<v8::FunctionTemplate> unrel_fun =
220 v8::FunctionTemplate::New(isolate);
221 // Install properties.
222 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
223 fun_proto->Set(v8_str("prop_sig"), callback_sig);
224 fun_proto->Set(v8_str("prop"), callback);
225 fun_proto->SetAccessorProperty(
226 v8_str("accessor_sig"), callback_sig, callback_sig);
227 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
228 // Instantiate templates.
229 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
230 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
231 // Setup global variables.
232 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
233 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
234 env->Global()->Set(v8_str("fun_instance"), fun_instance);
235 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
237 "var accessor_sig_key = 'accessor_sig';"
238 "var accessor_key = 'accessor';"
239 "var prop_sig_key = 'prop_sig';"
240 "var prop_key = 'prop';"
242 "function copy_props(obj) {"
243 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
244 " var source = Fun.prototype;"
245 " for (var i in keys) {"
246 " var key = keys[i];"
247 " var desc = Object.getOwnPropertyDescriptor(source, key);"
248 " Object.defineProperty(obj, key, desc);"
254 "var unrel = new UnrelFun();"
255 "copy_props(unrel);");
256 // Test with and without ICs
257 const char* test_objects[] = {
258 "fun_instance", "sub_fun_instance", "obj", "unrel" };
259 unsigned bad_signature_start_offset = 2;
260 for (unsigned i = 0; i < arraysize(test_objects); i++) {
261 i::ScopedVector<char> source(200);
263 source, "var test_object = %s; test_object", test_objects[i]);
264 Local<Value> test_object = CompileRun(source.start());
265 TestSignature("test_object.prop();", test_object, isolate);
266 TestSignature("test_object.accessor;", test_object, isolate);
267 TestSignature("test_object[accessor_key];", test_object, isolate);
268 TestSignature("test_object.accessor = 1;", test_object, isolate);
269 TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
270 if (i >= bad_signature_start_offset) test_object = Local<Value>();
271 TestSignature("test_object.prop_sig();", test_object, isolate);
272 TestSignature("test_object.accessor_sig;", test_object, isolate);
273 TestSignature("test_object[accessor_sig_key];", test_object, isolate);
274 TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
275 TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
280 THREADED_TEST(HulIgennem) {
282 v8::Isolate* isolate = env->GetIsolate();
283 v8::HandleScope scope(isolate);
284 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
285 Local<String> undef_str = undef->ToString(isolate);
286 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
287 undef_str->WriteUtf8(value);
288 CHECK_EQ(0, strcmp(value, "undefined"));
289 i::DeleteArray(value);
293 THREADED_TEST(Access) {
295 v8::Isolate* isolate = env->GetIsolate();
296 v8::HandleScope scope(isolate);
297 Local<v8::Object> obj = v8::Object::New(isolate);
298 Local<Value> foo_before = obj->Get(v8_str("foo"));
299 CHECK(foo_before->IsUndefined());
300 Local<String> bar_str = v8_str("bar");
301 obj->Set(v8_str("foo"), bar_str);
302 Local<Value> foo_after = obj->Get(v8_str("foo"));
303 CHECK(!foo_after->IsUndefined());
304 CHECK(foo_after->IsString());
305 CHECK(bar_str->Equals(foo_after));
309 THREADED_TEST(AccessElement) {
311 v8::HandleScope scope(env->GetIsolate());
312 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
313 Local<Value> before = obj->Get(1);
314 CHECK(before->IsUndefined());
315 Local<String> bar_str = v8_str("bar");
316 obj->Set(1, bar_str);
317 Local<Value> after = obj->Get(1);
318 CHECK(!after->IsUndefined());
319 CHECK(after->IsString());
320 CHECK(bar_str->Equals(after));
322 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
323 CHECK(v8_str("a")->Equals(value->Get(0)));
324 CHECK(v8_str("b")->Equals(value->Get(1)));
328 THREADED_TEST(Script) {
330 v8::HandleScope scope(env->GetIsolate());
331 const char* source = "1 + 2 + 3";
332 Local<Script> script = v8_compile(source);
333 CHECK_EQ(6, script->Run()->Int32Value());
337 class TestResource: public String::ExternalStringResource {
339 explicit TestResource(uint16_t* data, int* counter = NULL,
340 bool owning_data = true)
341 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
342 while (data[length_]) ++length_;
346 if (owning_data_) i::DeleteArray(data_);
347 if (counter_ != NULL) ++*counter_;
350 const uint16_t* data() const {
354 size_t length() const {
366 class TestOneByteResource : public String::ExternalOneByteStringResource {
368 explicit TestOneByteResource(const char* data, int* counter = NULL,
371 data_(data + offset),
372 length_(strlen(data) - offset),
375 ~TestOneByteResource() {
376 i::DeleteArray(orig_data_);
377 if (counter_ != NULL) ++*counter_;
380 const char* data() const {
384 size_t length() const {
389 const char* orig_data_;
396 THREADED_TEST(ScriptUsingStringResource) {
397 int dispose_count = 0;
398 const char* c_source = "1 + 2 * 3";
399 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
402 v8::HandleScope scope(env->GetIsolate());
403 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
404 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
405 Local<Script> script = v8_compile(source);
406 Local<Value> value = script->Run();
407 CHECK(value->IsNumber());
408 CHECK_EQ(7, value->Int32Value());
409 CHECK(source->IsExternal());
411 static_cast<TestResource*>(source->GetExternalStringResource()));
412 String::Encoding encoding = String::UNKNOWN_ENCODING;
413 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
414 source->GetExternalStringResourceBase(&encoding));
415 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
416 CcTest::heap()->CollectAllGarbage();
417 CHECK_EQ(0, dispose_count);
419 CcTest::i_isolate()->compilation_cache()->Clear();
420 CcTest::heap()->CollectAllAvailableGarbage();
421 CHECK_EQ(1, dispose_count);
425 THREADED_TEST(ScriptUsingOneByteStringResource) {
426 int dispose_count = 0;
427 const char* c_source = "1 + 2 * 3";
430 v8::HandleScope scope(env->GetIsolate());
431 TestOneByteResource* resource =
432 new TestOneByteResource(i::StrDup(c_source), &dispose_count);
433 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
434 CHECK(source->IsExternalOneByte());
435 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
436 source->GetExternalOneByteStringResource());
437 String::Encoding encoding = String::UNKNOWN_ENCODING;
438 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
439 source->GetExternalStringResourceBase(&encoding));
440 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
441 Local<Script> script = v8_compile(source);
442 Local<Value> value = script->Run();
443 CHECK(value->IsNumber());
444 CHECK_EQ(7, value->Int32Value());
445 CcTest::heap()->CollectAllGarbage();
446 CHECK_EQ(0, dispose_count);
448 CcTest::i_isolate()->compilation_cache()->Clear();
449 CcTest::heap()->CollectAllAvailableGarbage();
450 CHECK_EQ(1, dispose_count);
454 THREADED_TEST(ScriptMakingExternalString) {
455 int dispose_count = 0;
456 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
459 v8::HandleScope scope(env->GetIsolate());
460 Local<String> source =
461 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
462 // Trigger GCs so that the newly allocated string moves to old gen.
463 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
464 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
465 CHECK_EQ(source->IsExternal(), false);
466 CHECK_EQ(source->IsExternalOneByte(), false);
467 String::Encoding encoding = String::UNKNOWN_ENCODING;
468 CHECK(!source->GetExternalStringResourceBase(&encoding));
469 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
470 bool success = source->MakeExternal(new TestResource(two_byte_source,
473 Local<Script> script = v8_compile(source);
474 Local<Value> value = script->Run();
475 CHECK(value->IsNumber());
476 CHECK_EQ(7, value->Int32Value());
477 CcTest::heap()->CollectAllGarbage();
478 CHECK_EQ(0, dispose_count);
480 CcTest::i_isolate()->compilation_cache()->Clear();
481 CcTest::heap()->CollectAllGarbage();
482 CHECK_EQ(1, dispose_count);
486 THREADED_TEST(ScriptMakingExternalOneByteString) {
487 int dispose_count = 0;
488 const char* c_source = "1 + 2 * 3";
491 v8::HandleScope scope(env->GetIsolate());
492 Local<String> source = v8_str(c_source);
493 // Trigger GCs so that the newly allocated string moves to old gen.
494 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
495 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
496 bool success = source->MakeExternal(
497 new TestOneByteResource(i::StrDup(c_source), &dispose_count));
499 Local<Script> script = v8_compile(source);
500 Local<Value> value = script->Run();
501 CHECK(value->IsNumber());
502 CHECK_EQ(7, value->Int32Value());
503 CcTest::heap()->CollectAllGarbage();
504 CHECK_EQ(0, dispose_count);
506 CcTest::i_isolate()->compilation_cache()->Clear();
507 CcTest::heap()->CollectAllGarbage();
508 CHECK_EQ(1, dispose_count);
512 TEST(MakingExternalStringConditions) {
514 v8::HandleScope scope(env->GetIsolate());
516 // Free some space in the new space so that we can check freshness.
517 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
518 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
520 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
521 Local<String> small_string =
522 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
523 i::DeleteArray(two_byte_string);
525 // We should refuse to externalize newly created small string.
526 CHECK(!small_string->CanMakeExternal());
527 // Trigger GCs so that the newly allocated string moves to old gen.
528 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
529 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
530 // Old space strings should be accepted.
531 CHECK(small_string->CanMakeExternal());
533 two_byte_string = AsciiToTwoByteString("small string 2");
534 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
535 i::DeleteArray(two_byte_string);
537 // We should refuse externalizing newly created small string.
538 CHECK(!small_string->CanMakeExternal());
539 for (int i = 0; i < 100; i++) {
540 String::Value value(small_string);
542 // Frequently used strings should be accepted.
543 CHECK(small_string->CanMakeExternal());
545 const int buf_size = 10 * 1024;
546 char* buf = i::NewArray<char>(buf_size);
547 memset(buf, 'a', buf_size);
548 buf[buf_size - 1] = '\0';
550 two_byte_string = AsciiToTwoByteString(buf);
551 Local<String> large_string =
552 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
554 i::DeleteArray(two_byte_string);
555 // Large strings should be immediately accepted.
556 CHECK(large_string->CanMakeExternal());
560 TEST(MakingExternalOneByteStringConditions) {
562 v8::HandleScope scope(env->GetIsolate());
564 // Free some space in the new space so that we can check freshness.
565 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
566 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
568 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
569 // We should refuse to externalize newly created small string.
570 CHECK(!small_string->CanMakeExternal());
571 // Trigger GCs so that the newly allocated string moves to old gen.
572 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
573 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
574 // Old space strings should be accepted.
575 CHECK(small_string->CanMakeExternal());
577 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
578 // We should refuse externalizing newly created small string.
579 CHECK(!small_string->CanMakeExternal());
580 for (int i = 0; i < 100; i++) {
581 String::Value value(small_string);
583 // Frequently used strings should be accepted.
584 CHECK(small_string->CanMakeExternal());
586 const int buf_size = 10 * 1024;
587 char* buf = i::NewArray<char>(buf_size);
588 memset(buf, 'a', buf_size);
589 buf[buf_size - 1] = '\0';
590 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
592 // Large strings should be immediately accepted.
593 CHECK(large_string->CanMakeExternal());
597 TEST(MakingExternalUnalignedOneByteString) {
599 v8::HandleScope scope(env->GetIsolate());
601 CompileRun("function cons(a, b) { return a + b; }"
602 "function slice(a) { return a.substring(1); }");
603 // Create a cons string that will land in old pointer space.
604 Local<String> cons = Local<String>::Cast(CompileRun(
605 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
606 // Create a sliced string that will land in old pointer space.
607 Local<String> slice = Local<String>::Cast(CompileRun(
608 "slice('abcdefghijklmnopqrstuvwxyz');"));
610 // Trigger GCs so that the newly allocated string moves to old gen.
611 SimulateFullSpace(CcTest::heap()->old_space());
612 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
613 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
615 // Turn into external string with unaligned resource data.
616 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
618 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
620 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
622 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
625 // Trigger GCs and force evacuation.
626 CcTest::heap()->CollectAllGarbage();
627 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
631 THREADED_TEST(UsingExternalString) {
632 i::Factory* factory = CcTest::i_isolate()->factory();
634 v8::HandleScope scope(CcTest::isolate());
635 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
636 Local<String> string = String::NewExternal(
637 CcTest::isolate(), new TestResource(two_byte_string));
638 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
639 // Trigger GCs so that the newly allocated string moves to old gen.
640 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
641 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
642 i::Handle<i::String> isymbol =
643 factory->InternalizeString(istring);
644 CHECK(isymbol->IsInternalizedString());
646 CcTest::heap()->CollectAllGarbage();
647 CcTest::heap()->CollectAllGarbage();
651 THREADED_TEST(UsingExternalOneByteString) {
652 i::Factory* factory = CcTest::i_isolate()->factory();
654 v8::HandleScope scope(CcTest::isolate());
655 const char* one_byte_string = "test string";
656 Local<String> string = String::NewExternal(
657 CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
658 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
659 // Trigger GCs so that the newly allocated string moves to old gen.
660 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
661 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
662 i::Handle<i::String> isymbol =
663 factory->InternalizeString(istring);
664 CHECK(isymbol->IsInternalizedString());
666 CcTest::heap()->CollectAllGarbage();
667 CcTest::heap()->CollectAllGarbage();
671 class RandomLengthResource : public v8::String::ExternalStringResource {
673 explicit RandomLengthResource(int length) : length_(length) {}
674 virtual const uint16_t* data() const { return string_; }
675 virtual size_t length() const { return length_; }
678 uint16_t string_[10];
683 class RandomLengthOneByteResource
684 : public v8::String::ExternalOneByteStringResource {
686 explicit RandomLengthOneByteResource(int length) : length_(length) {}
687 virtual const char* data() const { return string_; }
688 virtual size_t length() const { return length_; }
696 THREADED_TEST(NewExternalForVeryLongString) {
697 auto isolate = CcTest::isolate();
699 v8::HandleScope scope(isolate);
700 v8::TryCatch try_catch(isolate);
701 RandomLengthOneByteResource r(1 << 30);
702 v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
703 CHECK(str.IsEmpty());
704 CHECK(!try_catch.HasCaught());
708 v8::HandleScope scope(isolate);
709 v8::TryCatch try_catch(isolate);
710 RandomLengthResource r(1 << 30);
711 v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
712 CHECK(str.IsEmpty());
713 CHECK(!try_catch.HasCaught());
718 THREADED_TEST(ScavengeExternalString) {
719 i::FLAG_stress_compaction = false;
720 i::FLAG_gc_global = false;
721 int dispose_count = 0;
722 bool in_new_space = false;
724 v8::HandleScope scope(CcTest::isolate());
725 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
726 Local<String> string = String::NewExternal(
727 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
728 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
729 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
730 in_new_space = CcTest::heap()->InNewSpace(*istring);
731 CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
732 CHECK_EQ(0, dispose_count);
734 CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
735 CHECK_EQ(1, dispose_count);
739 THREADED_TEST(ScavengeExternalOneByteString) {
740 i::FLAG_stress_compaction = false;
741 i::FLAG_gc_global = false;
742 int dispose_count = 0;
743 bool in_new_space = false;
745 v8::HandleScope scope(CcTest::isolate());
746 const char* one_byte_string = "test string";
747 Local<String> string = String::NewExternal(
749 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
750 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
751 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
752 in_new_space = CcTest::heap()->InNewSpace(*istring);
753 CHECK(in_new_space || CcTest::heap()->old_space()->Contains(*istring));
754 CHECK_EQ(0, dispose_count);
756 CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_SPACE);
757 CHECK_EQ(1, dispose_count);
761 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
763 // Only used by non-threaded tests, so it can use static fields.
764 static int dispose_calls;
765 static int dispose_count;
767 TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
768 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
772 if (dispose_) delete this;
779 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
780 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
783 TEST(ExternalStringWithDisposeHandling) {
784 const char* c_source = "1 + 2 * 3";
786 // Use a stack allocated external string resource allocated object.
787 TestOneByteResourceWithDisposeControl::dispose_count = 0;
788 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
789 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
792 v8::HandleScope scope(env->GetIsolate());
793 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
794 Local<Script> script = v8_compile(source);
795 Local<Value> value = script->Run();
796 CHECK(value->IsNumber());
797 CHECK_EQ(7, value->Int32Value());
798 CcTest::heap()->CollectAllAvailableGarbage();
799 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
801 CcTest::i_isolate()->compilation_cache()->Clear();
802 CcTest::heap()->CollectAllAvailableGarbage();
803 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
804 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
806 // Use a heap allocated external string resource allocated object.
807 TestOneByteResourceWithDisposeControl::dispose_count = 0;
808 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
809 TestOneByteResource* res_heap =
810 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
813 v8::HandleScope scope(env->GetIsolate());
814 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
815 Local<Script> script = v8_compile(source);
816 Local<Value> value = script->Run();
817 CHECK(value->IsNumber());
818 CHECK_EQ(7, value->Int32Value());
819 CcTest::heap()->CollectAllAvailableGarbage();
820 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
822 CcTest::i_isolate()->compilation_cache()->Clear();
823 CcTest::heap()->CollectAllAvailableGarbage();
824 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
825 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
829 THREADED_TEST(StringConcat) {
832 v8::HandleScope scope(env->GetIsolate());
833 const char* one_byte_string_1 = "function a_times_t";
834 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
835 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
836 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
837 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
838 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
839 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
840 Local<String> left = v8_str(one_byte_string_1);
842 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
843 Local<String> right =
844 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
845 i::DeleteArray(two_byte_source);
847 Local<String> source = String::Concat(left, right);
848 right = String::NewExternal(
850 new TestOneByteResource(i::StrDup(one_byte_extern_1)));
851 source = String::Concat(source, right);
852 right = String::NewExternal(
854 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
855 source = String::Concat(source, right);
856 right = v8_str(one_byte_string_2);
857 source = String::Concat(source, right);
859 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
860 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
861 i::DeleteArray(two_byte_source);
863 source = String::Concat(source, right);
864 right = String::NewExternal(
866 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
867 source = String::Concat(source, right);
868 Local<Script> script = v8_compile(source);
869 Local<Value> value = script->Run();
870 CHECK(value->IsNumber());
871 CHECK_EQ(68, value->Int32Value());
873 CcTest::i_isolate()->compilation_cache()->Clear();
874 CcTest::heap()->CollectAllGarbage();
875 CcTest::heap()->CollectAllGarbage();
879 THREADED_TEST(GlobalProperties) {
881 v8::HandleScope scope(env->GetIsolate());
882 v8::Handle<v8::Object> global = env->Global();
883 global->Set(v8_str("pi"), v8_num(3.1415926));
884 Local<Value> pi = global->Get(v8_str("pi"));
885 CHECK_EQ(3.1415926, pi->NumberValue());
889 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
890 i::Address callback) {
891 ApiTestFuzzer::Fuzz();
892 CheckReturnValue(info, callback);
893 info.GetReturnValue().Set(v8_str("bad value"));
894 info.GetReturnValue().Set(v8_num(102));
898 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
899 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
903 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
904 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
907 static void construct_callback(
908 const v8::FunctionCallbackInfo<Value>& info) {
909 ApiTestFuzzer::Fuzz();
910 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
911 info.This()->Set(v8_str("x"), v8_num(1));
912 info.This()->Set(v8_str("y"), v8_num(2));
913 info.GetReturnValue().Set(v8_str("bad value"));
914 info.GetReturnValue().Set(info.This());
918 static void Return239Callback(
919 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
920 ApiTestFuzzer::Fuzz();
921 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
922 info.GetReturnValue().Set(v8_str("bad value"));
923 info.GetReturnValue().Set(v8_num(239));
927 template<typename Handler>
928 static void TestFunctionTemplateInitializer(Handler handler,
930 // Test constructor calls.
933 v8::Isolate* isolate = env->GetIsolate();
934 v8::HandleScope scope(isolate);
936 Local<v8::FunctionTemplate> fun_templ =
937 v8::FunctionTemplate::New(isolate, handler);
938 Local<Function> fun = fun_templ->GetFunction();
939 env->Global()->Set(v8_str("obj"), fun);
940 Local<Script> script = v8_compile("obj()");
941 for (int i = 0; i < 30; i++) {
942 CHECK_EQ(102, script->Run()->Int32Value());
945 // Use SetCallHandler to initialize a function template, should work like
949 v8::Isolate* isolate = env->GetIsolate();
950 v8::HandleScope scope(isolate);
952 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
953 fun_templ->SetCallHandler(handler_2);
954 Local<Function> fun = fun_templ->GetFunction();
955 env->Global()->Set(v8_str("obj"), fun);
956 Local<Script> script = v8_compile("obj()");
957 for (int i = 0; i < 30; i++) {
958 CHECK_EQ(102, script->Run()->Int32Value());
964 template<typename Constructor, typename Accessor>
965 static void TestFunctionTemplateAccessor(Constructor constructor,
968 v8::HandleScope scope(env->GetIsolate());
970 Local<v8::FunctionTemplate> fun_templ =
971 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
972 fun_templ->SetClassName(v8_str("funky"));
973 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
974 Local<Function> fun = fun_templ->GetFunction();
975 env->Global()->Set(v8_str("obj"), fun);
976 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
977 CHECK(v8_str("[object funky]")->Equals(result));
978 CompileRun("var obj_instance = new obj();");
979 Local<Script> script;
980 script = v8_compile("obj_instance.x");
981 for (int i = 0; i < 30; i++) {
982 CHECK_EQ(1, script->Run()->Int32Value());
984 script = v8_compile("obj_instance.m");
985 for (int i = 0; i < 30; i++) {
986 CHECK_EQ(239, script->Run()->Int32Value());
991 THREADED_PROFILED_TEST(FunctionTemplate) {
992 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
993 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
997 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
998 ApiTestFuzzer::Fuzz();
999 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1000 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1004 template<typename Callback>
1005 static void TestSimpleCallback(Callback callback) {
1007 v8::Isolate* isolate = env->GetIsolate();
1008 v8::HandleScope scope(isolate);
1010 v8::Handle<v8::ObjectTemplate> object_template =
1011 v8::ObjectTemplate::New(isolate);
1012 object_template->Set(isolate, "callback",
1013 v8::FunctionTemplate::New(isolate, callback));
1014 v8::Local<v8::Object> object = object_template->NewInstance();
1015 (*env)->Global()->Set(v8_str("callback_object"), object);
1016 v8::Handle<v8::Script> script;
1017 script = v8_compile("callback_object.callback(17)");
1018 for (int i = 0; i < 30; i++) {
1019 CHECK_EQ(51424, script->Run()->Int32Value());
1021 script = v8_compile("callback_object.callback(17, 24)");
1022 for (int i = 0; i < 30; i++) {
1023 CHECK_EQ(51425, script->Run()->Int32Value());
1028 THREADED_PROFILED_TEST(SimpleCallback) {
1029 TestSimpleCallback(SimpleCallback);
1033 template<typename T>
1034 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1036 // constant return values
1037 static int32_t fast_return_value_int32 = 471;
1038 static uint32_t fast_return_value_uint32 = 571;
1039 static const double kFastReturnValueDouble = 2.7;
1040 // variable return values
1041 static bool fast_return_value_bool = false;
1042 enum ReturnValueOddball {
1044 kUndefinedReturnValue,
1045 kEmptyStringReturnValue
1047 static ReturnValueOddball fast_return_value_void;
1048 static bool fast_return_value_object_is_empty = false;
1050 // Helper function to avoid compiler error: insufficient contextual information
1051 // to determine type when applying FUNCTION_ADDR to a template function.
1052 static i::Address address_of(v8::FunctionCallback callback) {
1053 return FUNCTION_ADDR(callback);
1057 void FastReturnValueCallback<int32_t>(
1058 const v8::FunctionCallbackInfo<v8::Value>& info) {
1059 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1060 info.GetReturnValue().Set(fast_return_value_int32);
1064 void FastReturnValueCallback<uint32_t>(
1065 const v8::FunctionCallbackInfo<v8::Value>& info) {
1066 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1067 info.GetReturnValue().Set(fast_return_value_uint32);
1071 void FastReturnValueCallback<double>(
1072 const v8::FunctionCallbackInfo<v8::Value>& info) {
1073 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1074 info.GetReturnValue().Set(kFastReturnValueDouble);
1078 void FastReturnValueCallback<bool>(
1079 const v8::FunctionCallbackInfo<v8::Value>& info) {
1080 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1081 info.GetReturnValue().Set(fast_return_value_bool);
1085 void FastReturnValueCallback<void>(
1086 const v8::FunctionCallbackInfo<v8::Value>& info) {
1087 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1088 switch (fast_return_value_void) {
1089 case kNullReturnValue:
1090 info.GetReturnValue().SetNull();
1092 case kUndefinedReturnValue:
1093 info.GetReturnValue().SetUndefined();
1095 case kEmptyStringReturnValue:
1096 info.GetReturnValue().SetEmptyString();
1102 void FastReturnValueCallback<Object>(
1103 const v8::FunctionCallbackInfo<v8::Value>& info) {
1104 v8::Handle<v8::Object> object;
1105 if (!fast_return_value_object_is_empty) {
1106 object = Object::New(info.GetIsolate());
1108 info.GetReturnValue().Set(object);
1111 template<typename T>
1112 Handle<Value> TestFastReturnValues() {
1114 v8::Isolate* isolate = env->GetIsolate();
1115 v8::EscapableHandleScope scope(isolate);
1116 v8::Handle<v8::ObjectTemplate> object_template =
1117 v8::ObjectTemplate::New(isolate);
1118 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1119 object_template->Set(isolate, "callback",
1120 v8::FunctionTemplate::New(isolate, callback));
1121 v8::Local<v8::Object> object = object_template->NewInstance();
1122 (*env)->Global()->Set(v8_str("callback_object"), object);
1123 return scope.Escape(CompileRun("callback_object.callback()"));
1127 THREADED_PROFILED_TEST(FastReturnValues) {
1129 v8::Isolate* isolate = env->GetIsolate();
1130 v8::HandleScope scope(isolate);
1131 v8::Handle<v8::Value> value;
1132 // check int32_t and uint32_t
1133 int32_t int_values[] = {
1135 i::Smi::kMinValue, i::Smi::kMaxValue
1137 for (size_t i = 0; i < arraysize(int_values); i++) {
1138 for (int modifier = -1; modifier <= 1; modifier++) {
1139 int int_value = int_values[i] + modifier;
1141 fast_return_value_int32 = int_value;
1142 value = TestFastReturnValues<int32_t>();
1143 CHECK(value->IsInt32());
1144 CHECK(fast_return_value_int32 == value->Int32Value());
1146 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1147 value = TestFastReturnValues<uint32_t>();
1148 CHECK(value->IsUint32());
1149 CHECK(fast_return_value_uint32 == value->Uint32Value());
1153 value = TestFastReturnValues<double>();
1154 CHECK(value->IsNumber());
1155 CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
1156 // check bool values
1157 for (int i = 0; i < 2; i++) {
1158 fast_return_value_bool = i == 0;
1159 value = TestFastReturnValues<bool>();
1160 CHECK(value->IsBoolean());
1161 CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
1164 ReturnValueOddball oddballs[] = {
1166 kUndefinedReturnValue,
1167 kEmptyStringReturnValue
1169 for (size_t i = 0; i < arraysize(oddballs); i++) {
1170 fast_return_value_void = oddballs[i];
1171 value = TestFastReturnValues<void>();
1172 switch (fast_return_value_void) {
1173 case kNullReturnValue:
1174 CHECK(value->IsNull());
1176 case kUndefinedReturnValue:
1177 CHECK(value->IsUndefined());
1179 case kEmptyStringReturnValue:
1180 CHECK(value->IsString());
1181 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1186 fast_return_value_object_is_empty = false;
1187 value = TestFastReturnValues<Object>();
1188 CHECK(value->IsObject());
1189 fast_return_value_object_is_empty = true;
1190 value = TestFastReturnValues<Object>();
1191 CHECK(value->IsUndefined());
1195 THREADED_TEST(FunctionTemplateSetLength) {
1197 v8::Isolate* isolate = env->GetIsolate();
1198 v8::HandleScope scope(isolate);
1200 Local<v8::FunctionTemplate> fun_templ =
1201 v8::FunctionTemplate::New(isolate,
1203 Handle<v8::Value>(),
1204 Handle<v8::Signature>(),
1206 Local<Function> fun = fun_templ->GetFunction();
1207 env->Global()->Set(v8_str("obj"), fun);
1208 Local<Script> script = v8_compile("obj.length");
1209 CHECK_EQ(23, script->Run()->Int32Value());
1212 Local<v8::FunctionTemplate> fun_templ =
1213 v8::FunctionTemplate::New(isolate, handle_callback);
1214 fun_templ->SetLength(22);
1215 Local<Function> fun = fun_templ->GetFunction();
1216 env->Global()->Set(v8_str("obj"), fun);
1217 Local<Script> script = v8_compile("obj.length");
1218 CHECK_EQ(22, script->Run()->Int32Value());
1221 // Without setting length it defaults to 0.
1222 Local<v8::FunctionTemplate> fun_templ =
1223 v8::FunctionTemplate::New(isolate, handle_callback);
1224 Local<Function> fun = fun_templ->GetFunction();
1225 env->Global()->Set(v8_str("obj"), fun);
1226 Local<Script> script = v8_compile("obj.length");
1227 CHECK_EQ(0, script->Run()->Int32Value());
1232 static void* expected_ptr;
1233 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1234 void* ptr = v8::External::Cast(*args.Data())->Value();
1235 CHECK_EQ(expected_ptr, ptr);
1236 args.GetReturnValue().Set(true);
1240 static void TestExternalPointerWrapping() {
1242 v8::Isolate* isolate = env->GetIsolate();
1243 v8::HandleScope scope(isolate);
1245 v8::Handle<v8::Value> data =
1246 v8::External::New(isolate, expected_ptr);
1248 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1249 obj->Set(v8_str("func"),
1250 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1251 env->Global()->Set(v8_str("obj"), obj);
1254 "function foo() {\n"
1255 " for (var i = 0; i < 13; i++) obj.func();\n"
1257 "foo(), true")->BooleanValue());
1261 THREADED_TEST(ExternalWrap) {
1262 // Check heap allocated object.
1265 TestExternalPointerWrapping();
1268 // Check stack allocated object.
1270 expected_ptr = &foo;
1271 TestExternalPointerWrapping();
1273 // Check not aligned addresses.
1275 char* s = new char[n];
1276 for (int i = 0; i < n; i++) {
1277 expected_ptr = s + i;
1278 TestExternalPointerWrapping();
1283 // Check several invalid addresses.
1284 expected_ptr = reinterpret_cast<void*>(1);
1285 TestExternalPointerWrapping();
1287 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1288 TestExternalPointerWrapping();
1290 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1291 TestExternalPointerWrapping();
1293 #if defined(V8_HOST_ARCH_X64)
1294 // Check a value with a leading 1 bit in x64 Smi encoding.
1295 expected_ptr = reinterpret_cast<void*>(0x400000000);
1296 TestExternalPointerWrapping();
1298 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1299 TestExternalPointerWrapping();
1301 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1302 TestExternalPointerWrapping();
1307 THREADED_TEST(FindInstanceInPrototypeChain) {
1309 v8::Isolate* isolate = env->GetIsolate();
1310 v8::HandleScope scope(isolate);
1312 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1313 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1314 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1315 derived->Inherit(base);
1317 Local<v8::Function> base_function = base->GetFunction();
1318 Local<v8::Function> derived_function = derived->GetFunction();
1319 Local<v8::Function> other_function = other->GetFunction();
1321 Local<v8::Object> base_instance = base_function->NewInstance();
1322 Local<v8::Object> derived_instance = derived_function->NewInstance();
1323 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1324 Local<v8::Object> other_instance = other_function->NewInstance();
1325 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1326 other_instance->Set(v8_str("__proto__"), derived_instance2);
1328 // base_instance is only an instance of base.
1330 base_instance->Equals(base_instance->FindInstanceInPrototypeChain(base)));
1331 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1332 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1334 // derived_instance is an instance of base and derived.
1335 CHECK(derived_instance->Equals(
1336 derived_instance->FindInstanceInPrototypeChain(base)));
1337 CHECK(derived_instance->Equals(
1338 derived_instance->FindInstanceInPrototypeChain(derived)));
1339 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1341 // other_instance is an instance of other and its immediate
1342 // prototype derived_instance2 is an instance of base and derived.
1343 // Note, derived_instance is an instance of base and derived too,
1344 // but it comes after derived_instance2 in the prototype chain of
1346 CHECK(derived_instance2->Equals(
1347 other_instance->FindInstanceInPrototypeChain(base)));
1348 CHECK(derived_instance2->Equals(
1349 other_instance->FindInstanceInPrototypeChain(derived)));
1350 CHECK(other_instance->Equals(
1351 other_instance->FindInstanceInPrototypeChain(other)));
1355 THREADED_TEST(TinyInteger) {
1357 v8::Isolate* isolate = env->GetIsolate();
1358 v8::HandleScope scope(isolate);
1360 int32_t value = 239;
1361 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1362 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1364 value_obj = v8::Integer::New(isolate, value);
1365 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1369 THREADED_TEST(BigSmiInteger) {
1371 v8::HandleScope scope(env->GetIsolate());
1372 v8::Isolate* isolate = CcTest::isolate();
1374 int32_t value = i::Smi::kMaxValue;
1375 // We cannot add one to a Smi::kMaxValue without wrapping.
1376 if (i::SmiValuesAre31Bits()) {
1377 CHECK(i::Smi::IsValid(value));
1378 CHECK(!i::Smi::IsValid(value + 1));
1380 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1381 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1383 value_obj = v8::Integer::New(isolate, value);
1384 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1389 THREADED_TEST(BigInteger) {
1391 v8::HandleScope scope(env->GetIsolate());
1392 v8::Isolate* isolate = CcTest::isolate();
1394 // We cannot add one to a Smi::kMaxValue without wrapping.
1395 if (i::SmiValuesAre31Bits()) {
1396 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1397 // The code will not be run in that case, due to the "if" guard.
1399 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1400 CHECK(value > i::Smi::kMaxValue);
1401 CHECK(!i::Smi::IsValid(value));
1403 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1404 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1406 value_obj = v8::Integer::New(isolate, value);
1407 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1412 THREADED_TEST(TinyUnsignedInteger) {
1414 v8::HandleScope scope(env->GetIsolate());
1415 v8::Isolate* isolate = CcTest::isolate();
1417 uint32_t value = 239;
1419 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1420 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1422 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1423 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1427 THREADED_TEST(BigUnsignedSmiInteger) {
1429 v8::HandleScope scope(env->GetIsolate());
1430 v8::Isolate* isolate = CcTest::isolate();
1432 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1433 CHECK(i::Smi::IsValid(value));
1434 CHECK(!i::Smi::IsValid(value + 1));
1436 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1437 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1439 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1440 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1444 THREADED_TEST(BigUnsignedInteger) {
1446 v8::HandleScope scope(env->GetIsolate());
1447 v8::Isolate* isolate = CcTest::isolate();
1449 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1450 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1451 CHECK(!i::Smi::IsValid(value));
1453 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1454 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1456 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1457 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1461 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1463 v8::HandleScope scope(env->GetIsolate());
1464 v8::Isolate* isolate = CcTest::isolate();
1466 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1467 uint32_t value = INT32_MAX_AS_UINT + 1;
1468 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1470 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1471 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1473 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1474 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1478 THREADED_TEST(IsNativeError) {
1480 v8::HandleScope scope(env->GetIsolate());
1481 v8::Handle<Value> syntax_error = CompileRun(
1482 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1483 CHECK(syntax_error->IsNativeError());
1484 v8::Handle<Value> not_error = CompileRun("{a:42}");
1485 CHECK(!not_error->IsNativeError());
1486 v8::Handle<Value> not_object = CompileRun("42");
1487 CHECK(!not_object->IsNativeError());
1491 THREADED_TEST(IsGeneratorFunctionOrObject) {
1493 v8::HandleScope scope(env->GetIsolate());
1495 CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1496 v8::Handle<Value> gen = CompileRun("gen");
1497 v8::Handle<Value> genObj = CompileRun("gen()");
1498 v8::Handle<Value> object = CompileRun("{a:42}");
1499 v8::Handle<Value> func = CompileRun("func");
1501 CHECK(gen->IsGeneratorFunction());
1502 CHECK(gen->IsFunction());
1503 CHECK(!gen->IsGeneratorObject());
1505 CHECK(!genObj->IsGeneratorFunction());
1506 CHECK(!genObj->IsFunction());
1507 CHECK(genObj->IsGeneratorObject());
1509 CHECK(!object->IsGeneratorFunction());
1510 CHECK(!object->IsFunction());
1511 CHECK(!object->IsGeneratorObject());
1513 CHECK(!func->IsGeneratorFunction());
1514 CHECK(func->IsFunction());
1515 CHECK(!func->IsGeneratorObject());
1519 THREADED_TEST(ArgumentsObject) {
1521 v8::HandleScope scope(env->GetIsolate());
1522 v8::Handle<Value> arguments_object =
1523 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1524 CHECK(arguments_object->IsArgumentsObject());
1525 v8::Handle<Value> array = CompileRun("[1,2,3]");
1526 CHECK(!array->IsArgumentsObject());
1527 v8::Handle<Value> object = CompileRun("{a:42}");
1528 CHECK(!object->IsArgumentsObject());
1532 THREADED_TEST(IsMapOrSet) {
1534 v8::HandleScope scope(env->GetIsolate());
1535 v8::Handle<Value> map = CompileRun("new Map()");
1536 v8::Handle<Value> set = CompileRun("new Set()");
1537 v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1538 v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1539 CHECK(map->IsMap());
1540 CHECK(set->IsSet());
1541 CHECK(weak_map->IsWeakMap());
1542 CHECK(weak_set->IsWeakSet());
1544 CHECK(!map->IsSet());
1545 CHECK(!map->IsWeakMap());
1546 CHECK(!map->IsWeakSet());
1548 CHECK(!set->IsMap());
1549 CHECK(!set->IsWeakMap());
1550 CHECK(!set->IsWeakSet());
1552 CHECK(!weak_map->IsMap());
1553 CHECK(!weak_map->IsSet());
1554 CHECK(!weak_map->IsWeakSet());
1556 CHECK(!weak_set->IsMap());
1557 CHECK(!weak_set->IsSet());
1558 CHECK(!weak_set->IsWeakMap());
1560 v8::Handle<Value> object = CompileRun("{a:42}");
1561 CHECK(!object->IsMap());
1562 CHECK(!object->IsSet());
1563 CHECK(!object->IsWeakMap());
1564 CHECK(!object->IsWeakSet());
1568 THREADED_TEST(StringObject) {
1570 v8::HandleScope scope(env->GetIsolate());
1571 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1572 CHECK(boxed_string->IsStringObject());
1573 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1574 CHECK(!unboxed_string->IsStringObject());
1575 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1576 CHECK(!boxed_not_string->IsStringObject());
1577 v8::Handle<Value> not_object = CompileRun("0");
1578 CHECK(!not_object->IsStringObject());
1579 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1580 CHECK(!as_boxed.IsEmpty());
1581 Local<v8::String> the_string = as_boxed->ValueOf();
1582 CHECK(!the_string.IsEmpty());
1583 ExpectObject("\"test\"", the_string);
1584 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1585 CHECK(new_boxed_string->IsStringObject());
1586 as_boxed = new_boxed_string.As<v8::StringObject>();
1587 the_string = as_boxed->ValueOf();
1588 CHECK(!the_string.IsEmpty());
1589 ExpectObject("\"test\"", the_string);
1593 TEST(StringObjectDelete) {
1594 LocalContext context;
1595 v8::HandleScope scope(context->GetIsolate());
1596 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1597 CHECK(boxed_string->IsStringObject());
1598 v8::Handle<v8::Object> str_obj = boxed_string.As<v8::Object>();
1599 CHECK(!str_obj->Delete(2));
1600 CHECK(!str_obj->Delete(v8_num(2)));
1604 THREADED_TEST(NumberObject) {
1606 v8::HandleScope scope(env->GetIsolate());
1607 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1608 CHECK(boxed_number->IsNumberObject());
1609 v8::Handle<Value> unboxed_number = CompileRun("42");
1610 CHECK(!unboxed_number->IsNumberObject());
1611 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1612 CHECK(!boxed_not_number->IsNumberObject());
1613 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1614 CHECK(!as_boxed.IsEmpty());
1615 double the_number = as_boxed->ValueOf();
1616 CHECK_EQ(42.0, the_number);
1617 v8::Handle<v8::Value> new_boxed_number =
1618 v8::NumberObject::New(env->GetIsolate(), 43);
1619 CHECK(new_boxed_number->IsNumberObject());
1620 as_boxed = new_boxed_number.As<v8::NumberObject>();
1621 the_number = as_boxed->ValueOf();
1622 CHECK_EQ(43.0, the_number);
1626 THREADED_TEST(BooleanObject) {
1628 v8::HandleScope scope(env->GetIsolate());
1629 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1630 CHECK(boxed_boolean->IsBooleanObject());
1631 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1632 CHECK(!unboxed_boolean->IsBooleanObject());
1633 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1634 CHECK(!boxed_not_boolean->IsBooleanObject());
1635 v8::Handle<v8::BooleanObject> as_boxed =
1636 boxed_boolean.As<v8::BooleanObject>();
1637 CHECK(!as_boxed.IsEmpty());
1638 bool the_boolean = as_boxed->ValueOf();
1639 CHECK_EQ(true, the_boolean);
1640 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1641 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1642 CHECK(boxed_true->IsBooleanObject());
1643 CHECK(boxed_false->IsBooleanObject());
1644 as_boxed = boxed_true.As<v8::BooleanObject>();
1645 CHECK_EQ(true, as_boxed->ValueOf());
1646 as_boxed = boxed_false.As<v8::BooleanObject>();
1647 CHECK_EQ(false, as_boxed->ValueOf());
1651 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1653 v8::HandleScope scope(env->GetIsolate());
1655 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1656 CHECK(primitive_false->IsBoolean());
1657 CHECK(!primitive_false->IsBooleanObject());
1658 CHECK(!primitive_false->BooleanValue());
1659 CHECK(!primitive_false->IsTrue());
1660 CHECK(primitive_false->IsFalse());
1662 Local<Value> false_value = BooleanObject::New(false);
1663 CHECK(!false_value->IsBoolean());
1664 CHECK(false_value->IsBooleanObject());
1665 CHECK(false_value->BooleanValue());
1666 CHECK(!false_value->IsTrue());
1667 CHECK(!false_value->IsFalse());
1669 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1670 CHECK(!false_boolean_object->IsBoolean());
1671 CHECK(false_boolean_object->IsBooleanObject());
1672 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1673 // CHECK(false_boolean_object->BooleanValue());
1674 CHECK(!false_boolean_object->ValueOf());
1675 CHECK(!false_boolean_object->IsTrue());
1676 CHECK(!false_boolean_object->IsFalse());
1678 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1679 CHECK(primitive_true->IsBoolean());
1680 CHECK(!primitive_true->IsBooleanObject());
1681 CHECK(primitive_true->BooleanValue());
1682 CHECK(primitive_true->IsTrue());
1683 CHECK(!primitive_true->IsFalse());
1685 Local<Value> true_value = BooleanObject::New(true);
1686 CHECK(!true_value->IsBoolean());
1687 CHECK(true_value->IsBooleanObject());
1688 CHECK(true_value->BooleanValue());
1689 CHECK(!true_value->IsTrue());
1690 CHECK(!true_value->IsFalse());
1692 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1693 CHECK(!true_boolean_object->IsBoolean());
1694 CHECK(true_boolean_object->IsBooleanObject());
1695 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1696 // CHECK(true_boolean_object->BooleanValue());
1697 CHECK(true_boolean_object->ValueOf());
1698 CHECK(!true_boolean_object->IsTrue());
1699 CHECK(!true_boolean_object->IsFalse());
1703 THREADED_TEST(Number) {
1705 v8::HandleScope scope(env->GetIsolate());
1706 double PI = 3.1415926;
1707 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1708 CHECK_EQ(PI, pi_obj->NumberValue());
1712 THREADED_TEST(ToNumber) {
1714 v8::Isolate* isolate = CcTest::isolate();
1715 v8::HandleScope scope(isolate);
1716 Local<String> str = v8_str("3.1415926");
1717 CHECK_EQ(3.1415926, str->NumberValue());
1718 v8::Handle<v8::Boolean> t = v8::True(isolate);
1719 CHECK_EQ(1.0, t->NumberValue());
1720 v8::Handle<v8::Boolean> f = v8::False(isolate);
1721 CHECK_EQ(0.0, f->NumberValue());
1725 THREADED_TEST(Date) {
1727 v8::HandleScope scope(env->GetIsolate());
1728 double PI = 3.1415926;
1729 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1730 CHECK_EQ(3.0, date->NumberValue());
1731 date.As<v8::Date>()->Set(v8_str("property"),
1732 v8::Integer::New(env->GetIsolate(), 42));
1733 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1737 THREADED_TEST(Boolean) {
1739 v8::Isolate* isolate = env->GetIsolate();
1740 v8::HandleScope scope(isolate);
1741 v8::Handle<v8::Boolean> t = v8::True(isolate);
1743 v8::Handle<v8::Boolean> f = v8::False(isolate);
1745 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1746 CHECK(!u->BooleanValue());
1747 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1748 CHECK(!n->BooleanValue());
1749 v8::Handle<String> str1 = v8_str("");
1750 CHECK(!str1->BooleanValue());
1751 v8::Handle<String> str2 = v8_str("x");
1752 CHECK(str2->BooleanValue());
1753 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1754 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1755 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1756 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1757 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1761 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1762 ApiTestFuzzer::Fuzz();
1763 args.GetReturnValue().Set(v8_num(13.4));
1767 static void GetM(Local<String> name,
1768 const v8::PropertyCallbackInfo<v8::Value>& info) {
1769 ApiTestFuzzer::Fuzz();
1770 info.GetReturnValue().Set(v8_num(876));
1774 THREADED_TEST(GlobalPrototype) {
1775 v8::Isolate* isolate = CcTest::isolate();
1776 v8::HandleScope scope(isolate);
1777 v8::Handle<v8::FunctionTemplate> func_templ =
1778 v8::FunctionTemplate::New(isolate);
1779 func_templ->PrototypeTemplate()->Set(
1780 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1781 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1782 templ->Set(isolate, "x", v8_num(200));
1783 templ->SetAccessor(v8_str("m"), GetM);
1784 LocalContext env(0, templ);
1785 v8::Handle<Script> script(v8_compile("dummy()"));
1786 v8::Handle<Value> result(script->Run());
1787 CHECK_EQ(13.4, result->NumberValue());
1788 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1789 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1793 THREADED_TEST(ObjectTemplate) {
1794 v8::Isolate* isolate = CcTest::isolate();
1795 v8::HandleScope scope(isolate);
1796 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1797 v8::Local<v8::String> class_name =
1798 v8::String::NewFromUtf8(isolate, "the_class_name");
1799 fun->SetClassName(class_name);
1800 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun);
1801 templ1->Set(isolate, "x", v8_num(10));
1802 templ1->Set(isolate, "y", v8_num(13));
1804 Local<v8::Object> instance1 = templ1->NewInstance();
1805 CHECK(class_name->StrictEquals(instance1->GetConstructorName()));
1806 env->Global()->Set(v8_str("p"), instance1);
1807 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1808 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1809 Local<v8::FunctionTemplate> fun2 = v8::FunctionTemplate::New(isolate);
1810 fun2->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1811 Local<ObjectTemplate> templ2 = fun2->InstanceTemplate();
1812 templ2->Set(isolate, "a", v8_num(12));
1813 templ2->Set(isolate, "b", templ1);
1814 Local<v8::Object> instance2 = templ2->NewInstance();
1815 env->Global()->Set(v8_str("q"), instance2);
1816 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1817 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1818 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1819 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1823 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1824 ApiTestFuzzer::Fuzz();
1825 args.GetReturnValue().Set(v8_num(17.2));
1829 static void GetKnurd(Local<String> property,
1830 const v8::PropertyCallbackInfo<v8::Value>& info) {
1831 ApiTestFuzzer::Fuzz();
1832 info.GetReturnValue().Set(v8_num(15.2));
1836 THREADED_TEST(DescriptorInheritance) {
1837 v8::Isolate* isolate = CcTest::isolate();
1838 v8::HandleScope scope(isolate);
1839 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1840 super->PrototypeTemplate()->Set(isolate, "flabby",
1841 v8::FunctionTemplate::New(isolate,
1843 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1845 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1847 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1848 base1->Inherit(super);
1849 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1851 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1852 base2->Inherit(super);
1853 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1857 env->Global()->Set(v8_str("s"), super->GetFunction());
1858 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1859 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1861 // Checks right __proto__ chain.
1862 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1863 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1865 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1867 // Instance accessor should not be visible on function object or its prototype
1868 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1869 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1870 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1872 env->Global()->Set(v8_str("obj"),
1873 base1->GetFunction()->NewInstance());
1874 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1875 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1876 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1877 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1878 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1880 env->Global()->Set(v8_str("obj2"),
1881 base2->GetFunction()->NewInstance());
1882 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1883 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1884 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1885 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1886 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1888 // base1 and base2 cannot cross reference to each's prototype
1889 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1890 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1894 // Helper functions for Interceptor/Accessor interaction tests
1896 void SimpleAccessorGetter(Local<String> name,
1897 const v8::PropertyCallbackInfo<v8::Value>& info) {
1898 Handle<Object> self = Handle<Object>::Cast(info.This());
1899 info.GetReturnValue().Set(
1900 self->Get(String::Concat(v8_str("accessor_"), name)));
1903 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1904 const v8::PropertyCallbackInfo<void>& info) {
1905 Handle<Object> self = Handle<Object>::Cast(info.This());
1906 self->Set(String::Concat(v8_str("accessor_"), name), value);
1909 void SymbolAccessorGetter(Local<Name> name,
1910 const v8::PropertyCallbackInfo<v8::Value>& info) {
1911 CHECK(name->IsSymbol());
1912 Local<Symbol> sym = Local<Symbol>::Cast(name);
1913 if (sym->Name()->IsUndefined())
1915 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
1918 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
1919 const v8::PropertyCallbackInfo<void>& info) {
1920 CHECK(name->IsSymbol());
1921 Local<Symbol> sym = Local<Symbol>::Cast(name);
1922 if (sym->Name()->IsUndefined())
1924 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
1927 void SymbolAccessorGetterReturnsDefault(
1928 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1929 CHECK(name->IsSymbol());
1930 Local<Symbol> sym = Local<Symbol>::Cast(name);
1931 if (sym->Name()->IsUndefined()) return;
1932 info.GetReturnValue().Set(info.Data());
1935 static void ThrowingSymbolAccessorGetter(
1936 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1937 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
1941 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
1942 v8::Isolate* isolate = CcTest::isolate();
1943 v8::HandleScope scope(isolate);
1945 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
1946 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
1947 CHECK(a->map()->instance_descriptors()->IsFixedArray());
1948 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1949 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
1950 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1951 // But we should still have an ExecutableAccessorInfo.
1952 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
1953 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
1954 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
1955 CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
1959 THREADED_TEST(UndefinedIsNotEnumerable) {
1961 v8::HandleScope scope(env->GetIsolate());
1962 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
1963 CHECK(result->IsFalse());
1967 v8::Handle<Script> call_recursively_script;
1968 static const int kTargetRecursionDepth = 200; // near maximum
1971 static void CallScriptRecursivelyCall(
1972 const v8::FunctionCallbackInfo<v8::Value>& args) {
1973 ApiTestFuzzer::Fuzz();
1974 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1975 if (depth == kTargetRecursionDepth) return;
1976 args.This()->Set(v8_str("depth"),
1977 v8::Integer::New(args.GetIsolate(), depth + 1));
1978 args.GetReturnValue().Set(call_recursively_script->Run());
1982 static void CallFunctionRecursivelyCall(
1983 const v8::FunctionCallbackInfo<v8::Value>& args) {
1984 ApiTestFuzzer::Fuzz();
1985 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1986 if (depth == kTargetRecursionDepth) {
1987 printf("[depth = %d]\n", depth);
1990 args.This()->Set(v8_str("depth"),
1991 v8::Integer::New(args.GetIsolate(), depth + 1));
1992 v8::Handle<Value> function =
1993 args.This()->Get(v8_str("callFunctionRecursively"));
1994 args.GetReturnValue().Set(
1995 function.As<Function>()->Call(args.This(), 0, NULL));
1999 THREADED_TEST(DeepCrossLanguageRecursion) {
2000 v8::Isolate* isolate = CcTest::isolate();
2001 v8::HandleScope scope(isolate);
2002 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2003 global->Set(v8_str("callScriptRecursively"),
2004 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2005 global->Set(v8_str("callFunctionRecursively"),
2006 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2007 LocalContext env(NULL, global);
2009 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2010 call_recursively_script = v8_compile("callScriptRecursively()");
2011 call_recursively_script->Run();
2012 call_recursively_script = v8::Handle<Script>();
2014 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2015 CompileRun("callFunctionRecursively()");
2019 static void ThrowingPropertyHandlerGet(
2020 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2021 // Since this interceptor is used on "with" objects, the runtime will look up
2022 // @@unscopables. Punt.
2023 if (key->IsSymbol()) return;
2024 ApiTestFuzzer::Fuzz();
2025 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2029 static void ThrowingPropertyHandlerSet(
2030 Local<Name> key, Local<Value>,
2031 const v8::PropertyCallbackInfo<v8::Value>& info) {
2032 info.GetIsolate()->ThrowException(key);
2033 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2037 THREADED_TEST(CallbackExceptionRegression) {
2038 v8::Isolate* isolate = CcTest::isolate();
2039 v8::HandleScope scope(isolate);
2040 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2041 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2042 ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2044 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2045 v8::Handle<Value> otto =
2046 CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2047 CHECK(v8_str("otto")->Equals(otto));
2048 v8::Handle<Value> netto =
2049 CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2050 CHECK(v8_str("netto")->Equals(netto));
2054 THREADED_TEST(FunctionPrototype) {
2055 v8::Isolate* isolate = CcTest::isolate();
2056 v8::HandleScope scope(isolate);
2057 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2058 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2060 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2061 Local<Script> script = v8_compile("Foo.prototype.plak");
2062 CHECK_EQ(script->Run()->Int32Value(), 321);
2066 THREADED_TEST(InternalFields) {
2068 v8::Isolate* isolate = env->GetIsolate();
2069 v8::HandleScope scope(isolate);
2071 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2072 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2073 instance_templ->SetInternalFieldCount(1);
2074 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2075 CHECK_EQ(1, obj->InternalFieldCount());
2076 CHECK(obj->GetInternalField(0)->IsUndefined());
2077 obj->SetInternalField(0, v8_num(17));
2078 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2082 THREADED_TEST(GlobalObjectInternalFields) {
2083 v8::Isolate* isolate = CcTest::isolate();
2084 v8::HandleScope scope(isolate);
2085 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2086 global_template->SetInternalFieldCount(1);
2087 LocalContext env(NULL, global_template);
2088 v8::Handle<v8::Object> global_proxy = env->Global();
2089 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2090 CHECK_EQ(1, global->InternalFieldCount());
2091 CHECK(global->GetInternalField(0)->IsUndefined());
2092 global->SetInternalField(0, v8_num(17));
2093 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2097 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2099 v8::HandleScope scope(CcTest::isolate());
2101 v8::Local<v8::Object> global = env->Global();
2102 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2103 CHECK(global->HasRealIndexedProperty(0));
2107 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2109 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2110 obj->SetAlignedPointerInInternalField(0, value);
2111 CcTest::heap()->CollectAllGarbage();
2112 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2116 THREADED_TEST(InternalFieldsAlignedPointers) {
2118 v8::Isolate* isolate = env->GetIsolate();
2119 v8::HandleScope scope(isolate);
2121 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2122 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2123 instance_templ->SetInternalFieldCount(1);
2124 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2125 CHECK_EQ(1, obj->InternalFieldCount());
2127 CheckAlignedPointerInInternalField(obj, NULL);
2129 int* heap_allocated = new int[100];
2130 CheckAlignedPointerInInternalField(obj, heap_allocated);
2131 delete[] heap_allocated;
2133 int stack_allocated[100];
2134 CheckAlignedPointerInInternalField(obj, stack_allocated);
2136 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2137 CheckAlignedPointerInInternalField(obj, huge);
2139 v8::Global<v8::Object> persistent(isolate, obj);
2140 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2141 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2145 static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2147 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2148 (*env)->SetAlignedPointerInEmbedderData(index, value);
2149 CcTest::heap()->CollectAllGarbage();
2150 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2154 static void* AlignedTestPointer(int i) {
2155 return reinterpret_cast<void*>(i * 1234);
2159 THREADED_TEST(EmbedderDataAlignedPointers) {
2161 v8::HandleScope scope(env->GetIsolate());
2163 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2165 int* heap_allocated = new int[100];
2166 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2167 delete[] heap_allocated;
2169 int stack_allocated[100];
2170 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2172 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2173 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2175 // Test growing of the embedder data's backing store.
2176 for (int i = 0; i < 100; i++) {
2177 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2179 CcTest::heap()->CollectAllGarbage();
2180 for (int i = 0; i < 100; i++) {
2181 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2186 static void CheckEmbedderData(LocalContext* env, int index,
2187 v8::Handle<Value> data) {
2188 (*env)->SetEmbedderData(index, data);
2189 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2193 THREADED_TEST(EmbedderData) {
2195 v8::Isolate* isolate = env->GetIsolate();
2196 v8::HandleScope scope(isolate);
2199 &env, 3, v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2200 CheckEmbedderData(&env, 2,
2201 v8::String::NewFromUtf8(isolate, "over the lazy dog."));
2202 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2203 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2207 THREADED_TEST(GetIsolate) {
2209 v8::Isolate* isolate = env->GetIsolate();
2210 v8::HandleScope scope(isolate);
2211 Local<v8::Object> obj = v8::Object::New(isolate);
2212 CHECK_EQ(isolate, obj->GetIsolate());
2213 CHECK_EQ(isolate, CcTest::global()->GetIsolate());
2217 THREADED_TEST(IdentityHash) {
2219 v8::Isolate* isolate = env->GetIsolate();
2220 v8::HandleScope scope(isolate);
2222 // Ensure that the test starts with an fresh heap to test whether the hash
2223 // code is based on the address.
2224 CcTest::heap()->CollectAllGarbage();
2225 Local<v8::Object> obj = v8::Object::New(isolate);
2226 int hash = obj->GetIdentityHash();
2227 int hash1 = obj->GetIdentityHash();
2228 CHECK_EQ(hash, hash1);
2229 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2230 // Since the identity hash is essentially a random number two consecutive
2231 // objects should not be assigned the same hash code. If the test below fails
2232 // the random number generator should be evaluated.
2233 CHECK_NE(hash, hash2);
2234 CcTest::heap()->CollectAllGarbage();
2235 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2236 // Make sure that the identity hash is not based on the initial address of
2237 // the object alone. If the test below fails the random number generator
2238 // should be evaluated.
2239 CHECK_NE(hash, hash3);
2240 int hash4 = obj->GetIdentityHash();
2241 CHECK_EQ(hash, hash4);
2243 // Check identity hashes behaviour in the presence of JS accessors.
2244 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2246 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2247 Local<v8::Object> o1 = v8::Object::New(isolate);
2248 Local<v8::Object> o2 = v8::Object::New(isolate);
2249 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2253 "function cnst() { return 42; };\n"
2254 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2255 Local<v8::Object> o1 = v8::Object::New(isolate);
2256 Local<v8::Object> o2 = v8::Object::New(isolate);
2257 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2262 void GlobalProxyIdentityHash(bool set_in_js) {
2264 v8::Isolate* isolate = env->GetIsolate();
2265 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2266 v8::HandleScope scope(isolate);
2267 Handle<Object> global_proxy = env->Global();
2268 i::Handle<i::Object> i_global_proxy = v8::Utils::OpenHandle(*global_proxy);
2269 env->Global()->Set(v8_str("global"), global_proxy);
2270 i::Handle<i::Object> original_hash;
2272 CompileRun("var m = new Set(); m.add(global);");
2273 original_hash = i::Handle<i::Object>(i_global_proxy->GetHash(), i_isolate);
2275 original_hash = i::Handle<i::Object>(
2276 i::Object::GetOrCreateHash(i_isolate, i_global_proxy));
2278 CHECK(original_hash->IsSmi());
2279 int32_t hash1 = i::Handle<i::Smi>::cast(original_hash)->value();
2280 // Hash should be retained after being detached.
2281 env->DetachGlobal();
2282 int hash2 = global_proxy->GetIdentityHash();
2283 CHECK_EQ(hash1, hash2);
2285 // Re-attach global proxy to a new context, hash should stay the same.
2286 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2287 int hash3 = global_proxy->GetIdentityHash();
2288 CHECK_EQ(hash1, hash3);
2293 THREADED_TEST(GlobalProxyIdentityHash) {
2294 GlobalProxyIdentityHash(true);
2295 GlobalProxyIdentityHash(false);
2299 TEST(SymbolIdentityHash) {
2301 v8::Isolate* isolate = env->GetIsolate();
2302 v8::HandleScope scope(isolate);
2305 Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
2306 int hash = symbol->GetIdentityHash();
2307 int hash1 = symbol->GetIdentityHash();
2308 CHECK_EQ(hash, hash1);
2309 CcTest::heap()->CollectAllGarbage();
2310 int hash3 = symbol->GetIdentityHash();
2311 CHECK_EQ(hash, hash3);
2315 v8::Handle<v8::Symbol> js_symbol =
2316 CompileRun("Symbol('foo')").As<v8::Symbol>();
2317 int hash = js_symbol->GetIdentityHash();
2318 int hash1 = js_symbol->GetIdentityHash();
2319 CHECK_EQ(hash, hash1);
2320 CcTest::heap()->CollectAllGarbage();
2321 int hash3 = js_symbol->GetIdentityHash();
2322 CHECK_EQ(hash, hash3);
2327 TEST(StringIdentityHash) {
2329 v8::Isolate* isolate = env->GetIsolate();
2330 v8::HandleScope scope(isolate);
2332 Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
2333 int hash = str->GetIdentityHash();
2334 int hash1 = str->GetIdentityHash();
2335 CHECK_EQ(hash, hash1);
2336 CcTest::heap()->CollectAllGarbage();
2337 int hash3 = str->GetIdentityHash();
2338 CHECK_EQ(hash, hash3);
2340 Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
2341 int hash4 = str2->GetIdentityHash();
2342 CHECK_EQ(hash, hash4);
2346 THREADED_TEST(SymbolProperties) {
2348 v8::Isolate* isolate = env->GetIsolate();
2349 v8::HandleScope scope(isolate);
2351 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2352 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2353 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
2354 v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
2356 CcTest::heap()->CollectAllGarbage();
2358 // Check basic symbol functionality.
2359 CHECK(sym1->IsSymbol());
2360 CHECK(sym2->IsSymbol());
2361 CHECK(!obj->IsSymbol());
2363 CHECK(sym1->Equals(sym1));
2364 CHECK(sym2->Equals(sym2));
2365 CHECK(!sym1->Equals(sym2));
2366 CHECK(!sym2->Equals(sym1));
2367 CHECK(sym1->StrictEquals(sym1));
2368 CHECK(sym2->StrictEquals(sym2));
2369 CHECK(!sym1->StrictEquals(sym2));
2370 CHECK(!sym2->StrictEquals(sym1));
2372 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2374 v8::Local<v8::Value> sym_val = sym2;
2375 CHECK(sym_val->IsSymbol());
2376 CHECK(sym_val->Equals(sym2));
2377 CHECK(sym_val->StrictEquals(sym2));
2378 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2380 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2381 CHECK(sym_obj->IsSymbolObject());
2382 CHECK(!sym2->IsSymbolObject());
2383 CHECK(!obj->IsSymbolObject());
2384 CHECK(!sym_obj->Equals(sym2));
2385 CHECK(!sym_obj->StrictEquals(sym2));
2386 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2387 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2389 // Make sure delete of a non-existent symbol property works.
2390 CHECK(obj->Delete(sym1));
2391 CHECK(!obj->Has(sym1));
2393 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2394 CHECK(obj->Has(sym1));
2395 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2396 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2397 CHECK(obj->Has(sym1));
2398 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2399 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2401 CHECK_EQ(0u, obj->GetOwnPropertyNames()->Length());
2402 unsigned num_props = obj->GetPropertyNames()->Length();
2403 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2404 v8::Integer::New(isolate, 20)));
2405 CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2406 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2408 CcTest::heap()->CollectAllGarbage();
2410 CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2411 CHECK(obj->Get(sym3)->IsUndefined());
2412 CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2413 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2414 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2415 ->Equals(v8::Integer::New(isolate, 42)));
2417 // Add another property and delete it afterwards to force the object in
2419 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2420 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2421 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2422 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2423 CHECK_EQ(2u, obj->GetOwnPropertyNames()->Length());
2425 CHECK(obj->Has(sym1));
2426 CHECK(obj->Has(sym2));
2427 CHECK(obj->Has(sym3));
2428 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2429 CHECK(obj->Delete(sym2));
2430 CHECK(obj->Has(sym1));
2431 CHECK(!obj->Has(sym2));
2432 CHECK(obj->Has(sym3));
2433 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2434 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2435 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2436 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2437 ->Equals(v8::Integer::New(isolate, 42)));
2438 CHECK_EQ(2u, obj->GetOwnPropertyNames()->Length());
2440 // Symbol properties are inherited.
2441 v8::Local<v8::Object> child = v8::Object::New(isolate);
2442 child->SetPrototype(obj);
2443 CHECK(child->Has(sym1));
2444 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2445 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2446 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2447 ->Equals(v8::Integer::New(isolate, 42)));
2448 CHECK_EQ(0u, child->GetOwnPropertyNames()->Length());
2452 THREADED_TEST(SymbolTemplateProperties) {
2454 v8::Isolate* isolate = env->GetIsolate();
2455 v8::HandleScope scope(isolate);
2456 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
2457 v8::Local<v8::Name> name = v8::Symbol::New(isolate);
2458 CHECK(!name.IsEmpty());
2459 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
2460 v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
2461 CHECK(!new_instance.IsEmpty());
2462 CHECK(new_instance->Has(name));
2466 THREADED_TEST(GlobalSymbols) {
2468 v8::Isolate* isolate = env->GetIsolate();
2469 v8::HandleScope scope(isolate);
2471 v8::Local<String> name = v8_str("my-symbol");
2472 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2473 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2474 CHECK(glob2->SameValue(glob));
2476 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2477 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2478 CHECK(glob_api2->SameValue(glob_api));
2479 CHECK(!glob_api->SameValue(glob));
2481 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2482 CHECK(!sym->SameValue(glob));
2484 CompileRun("var sym2 = Symbol.for('my-symbol')");
2485 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2486 CHECK(sym2->SameValue(glob));
2487 CHECK(!sym2->SameValue(glob_api));
2491 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
2494 v8::Isolate* isolate = env->GetIsolate();
2495 v8::HandleScope scope(isolate);
2497 v8::Local<v8::Symbol> symbol = getter(isolate);
2498 std::string script = std::string("var sym = ") + name;
2499 CompileRun(script.c_str());
2500 v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
2502 CHECK(!value.IsEmpty());
2503 CHECK(!symbol.IsEmpty());
2504 CHECK(value->SameValue(symbol));
2508 THREADED_TEST(WellKnownSymbols) {
2509 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
2510 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
2514 class ScopedArrayBufferContents {
2516 explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
2517 : contents_(contents) {}
2518 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2519 void* Data() const { return contents_.Data(); }
2520 size_t ByteLength() const { return contents_.ByteLength(); }
2523 const v8::ArrayBuffer::Contents contents_;
2526 template <typename T>
2527 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2528 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2529 for (int i = 0; i < value->InternalFieldCount(); i++) {
2530 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2535 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2537 v8::Isolate* isolate = env->GetIsolate();
2538 v8::HandleScope handle_scope(isolate);
2540 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2541 CheckInternalFieldsAreZero(ab);
2542 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2543 CHECK(!ab->IsExternal());
2544 CcTest::heap()->CollectAllGarbage();
2546 ScopedArrayBufferContents ab_contents(ab->Externalize());
2547 CHECK(ab->IsExternal());
2549 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2550 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2551 DCHECK(data != NULL);
2552 env->Global()->Set(v8_str("ab"), ab);
2554 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2555 CHECK_EQ(1024, result->Int32Value());
2557 result = CompileRun(
2558 "var u8 = new Uint8Array(ab);"
2562 CHECK_EQ(1024, result->Int32Value());
2563 CHECK_EQ(0xFF, data[0]);
2564 CHECK_EQ(0xAA, data[1]);
2567 result = CompileRun("u8[0] + u8[1]");
2568 CHECK_EQ(0xDD, result->Int32Value());
2572 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2574 v8::Isolate* isolate = env->GetIsolate();
2575 v8::HandleScope handle_scope(isolate);
2578 v8::Local<v8::Value> result = CompileRun(
2579 "var ab1 = new ArrayBuffer(2);"
2580 "var u8_a = new Uint8Array(ab1);"
2582 "u8_a[1] = 0xFF; u8_a.buffer");
2583 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2584 CheckInternalFieldsAreZero(ab1);
2585 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2586 CHECK(!ab1->IsExternal());
2587 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2588 CHECK(ab1->IsExternal());
2590 result = CompileRun("ab1.byteLength");
2591 CHECK_EQ(2, result->Int32Value());
2592 result = CompileRun("u8_a[0]");
2593 CHECK_EQ(0xAA, result->Int32Value());
2594 result = CompileRun("u8_a[1]");
2595 CHECK_EQ(0xFF, result->Int32Value());
2596 result = CompileRun(
2597 "var u8_b = new Uint8Array(ab1);"
2600 CHECK_EQ(0xBB, result->Int32Value());
2601 result = CompileRun("u8_b[1]");
2602 CHECK_EQ(0xFF, result->Int32Value());
2604 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2605 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2606 CHECK_EQ(0xBB, ab1_data[0]);
2607 CHECK_EQ(0xFF, ab1_data[1]);
2610 result = CompileRun("u8_a[0] + u8_a[1]");
2611 CHECK_EQ(0xDD, result->Int32Value());
2615 THREADED_TEST(ArrayBuffer_External) {
2617 v8::Isolate* isolate = env->GetIsolate();
2618 v8::HandleScope handle_scope(isolate);
2620 i::ScopedVector<uint8_t> my_data(100);
2621 memset(my_data.start(), 0, 100);
2622 Local<v8::ArrayBuffer> ab3 =
2623 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
2624 CheckInternalFieldsAreZero(ab3);
2625 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2626 CHECK(ab3->IsExternal());
2628 env->Global()->Set(v8_str("ab3"), ab3);
2630 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2631 CHECK_EQ(100, result->Int32Value());
2633 result = CompileRun(
2634 "var u8_b = new Uint8Array(ab3);"
2638 CHECK_EQ(100, result->Int32Value());
2639 CHECK_EQ(0xBB, my_data[0]);
2640 CHECK_EQ(0xCC, my_data[1]);
2643 result = CompileRun("u8_b[0] + u8_b[1]");
2644 CHECK_EQ(0xDD, result->Int32Value());
2648 THREADED_TEST(ArrayBuffer_DisableNeuter) {
2650 v8::Isolate* isolate = env->GetIsolate();
2651 v8::HandleScope handle_scope(isolate);
2653 i::ScopedVector<uint8_t> my_data(100);
2654 memset(my_data.start(), 0, 100);
2655 Local<v8::ArrayBuffer> ab =
2656 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
2657 CHECK(ab->IsNeuterable());
2659 i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
2660 buf->set_is_neuterable(false);
2662 CHECK(!ab->IsNeuterable());
2666 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
2667 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
2668 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
2672 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
2673 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
2674 CHECK_EQ(0, static_cast<int>(ta->Length()));
2675 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
2679 static void CheckIsTypedArrayVarNeutered(const char* name) {
2680 i::ScopedVector<char> source(1024);
2682 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
2684 CHECK(CompileRun(source.start())->IsTrue());
2685 v8::Handle<v8::TypedArray> ta =
2686 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
2687 CheckIsNeutered(ta);
2691 template <typename TypedArray, int kElementSize>
2692 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
2693 int byteOffset, int length) {
2694 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
2695 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
2696 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
2697 CHECK_EQ(length, static_cast<int>(ta->Length()));
2698 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
2703 THREADED_TEST(ArrayBuffer_NeuteringApi) {
2705 v8::Isolate* isolate = env->GetIsolate();
2706 v8::HandleScope handle_scope(isolate);
2708 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
2710 v8::Handle<v8::Uint8Array> u8a =
2711 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
2712 v8::Handle<v8::Uint8ClampedArray> u8c =
2713 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
2714 v8::Handle<v8::Int8Array> i8a =
2715 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
2717 v8::Handle<v8::Uint16Array> u16a =
2718 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
2719 v8::Handle<v8::Int16Array> i16a =
2720 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
2722 v8::Handle<v8::Uint32Array> u32a =
2723 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
2724 v8::Handle<v8::Int32Array> i32a =
2725 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
2727 v8::Handle<v8::Float32Array> f32a =
2728 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
2729 v8::Handle<v8::Float64Array> f64a =
2730 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
2732 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
2733 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
2734 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
2735 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
2737 ScopedArrayBufferContents contents(buffer->Externalize());
2739 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
2740 CheckIsNeutered(u8a);
2741 CheckIsNeutered(u8c);
2742 CheckIsNeutered(i8a);
2743 CheckIsNeutered(u16a);
2744 CheckIsNeutered(i16a);
2745 CheckIsNeutered(u32a);
2746 CheckIsNeutered(i32a);
2747 CheckIsNeutered(f32a);
2748 CheckIsNeutered(f64a);
2749 CheckDataViewIsNeutered(dv);
2753 THREADED_TEST(ArrayBuffer_NeuteringScript) {
2755 v8::Isolate* isolate = env->GetIsolate();
2756 v8::HandleScope handle_scope(isolate);
2759 "var ab = new ArrayBuffer(1024);"
2760 "var u8a = new Uint8Array(ab, 1, 1023);"
2761 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
2762 "var i8a = new Int8Array(ab, 1, 1023);"
2763 "var u16a = new Uint16Array(ab, 2, 511);"
2764 "var i16a = new Int16Array(ab, 2, 511);"
2765 "var u32a = new Uint32Array(ab, 4, 255);"
2766 "var i32a = new Int32Array(ab, 4, 255);"
2767 "var f32a = new Float32Array(ab, 4, 255);"
2768 "var f64a = new Float64Array(ab, 8, 127);"
2769 "var dv = new DataView(ab, 1, 1023);");
2771 v8::Handle<v8::ArrayBuffer> ab =
2772 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
2774 v8::Handle<v8::DataView> dv =
2775 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
2777 ScopedArrayBufferContents contents(ab->Externalize());
2779 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
2780 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
2782 CheckIsTypedArrayVarNeutered("u8a");
2783 CheckIsTypedArrayVarNeutered("u8c");
2784 CheckIsTypedArrayVarNeutered("i8a");
2785 CheckIsTypedArrayVarNeutered("u16a");
2786 CheckIsTypedArrayVarNeutered("i16a");
2787 CheckIsTypedArrayVarNeutered("u32a");
2788 CheckIsTypedArrayVarNeutered("i32a");
2789 CheckIsTypedArrayVarNeutered("f32a");
2790 CheckIsTypedArrayVarNeutered("f64a");
2792 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
2793 CheckDataViewIsNeutered(dv);
2797 class ScopedSharedArrayBufferContents {
2799 explicit ScopedSharedArrayBufferContents(
2800 const v8::SharedArrayBuffer::Contents& contents)
2801 : contents_(contents) {}
2802 ~ScopedSharedArrayBufferContents() { free(contents_.Data()); }
2803 void* Data() const { return contents_.Data(); }
2804 size_t ByteLength() const { return contents_.ByteLength(); }
2807 const v8::SharedArrayBuffer::Contents contents_;
2811 THREADED_TEST(SharedArrayBuffer_ApiInternalToExternal) {
2812 i::FLAG_harmony_sharedarraybuffer = true;
2814 v8::Isolate* isolate = env->GetIsolate();
2815 v8::HandleScope handle_scope(isolate);
2817 Local<v8::SharedArrayBuffer> ab = v8::SharedArrayBuffer::New(isolate, 1024);
2818 CheckInternalFieldsAreZero(ab);
2819 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2820 CHECK(!ab->IsExternal());
2821 CcTest::heap()->CollectAllGarbage();
2823 ScopedSharedArrayBufferContents ab_contents(ab->Externalize());
2824 CHECK(ab->IsExternal());
2826 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2827 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2828 DCHECK(data != NULL);
2829 env->Global()->Set(v8_str("ab"), ab);
2831 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2832 CHECK_EQ(1024, result->Int32Value());
2834 result = CompileRun(
2835 "var u8 = new Uint8Array(ab);"
2839 CHECK_EQ(1024, result->Int32Value());
2840 CHECK_EQ(0xFF, data[0]);
2841 CHECK_EQ(0xAA, data[1]);
2844 result = CompileRun("u8[0] + u8[1]");
2845 CHECK_EQ(0xDD, result->Int32Value());
2849 THREADED_TEST(SharedArrayBuffer_JSInternalToExternal) {
2850 i::FLAG_harmony_sharedarraybuffer = true;
2852 v8::Isolate* isolate = env->GetIsolate();
2853 v8::HandleScope handle_scope(isolate);
2856 v8::Local<v8::Value> result = CompileRun(
2857 "var ab1 = new SharedArrayBuffer(2);"
2858 "var u8_a = new Uint8Array(ab1);"
2860 "u8_a[1] = 0xFF; u8_a.buffer");
2861 Local<v8::SharedArrayBuffer> ab1 = Local<v8::SharedArrayBuffer>::Cast(result);
2862 CheckInternalFieldsAreZero(ab1);
2863 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2864 CHECK(!ab1->IsExternal());
2865 ScopedSharedArrayBufferContents ab1_contents(ab1->Externalize());
2866 CHECK(ab1->IsExternal());
2868 result = CompileRun("ab1.byteLength");
2869 CHECK_EQ(2, result->Int32Value());
2870 result = CompileRun("u8_a[0]");
2871 CHECK_EQ(0xAA, result->Int32Value());
2872 result = CompileRun("u8_a[1]");
2873 CHECK_EQ(0xFF, result->Int32Value());
2874 result = CompileRun(
2875 "var u8_b = new Uint8Array(ab1);"
2878 CHECK_EQ(0xBB, result->Int32Value());
2879 result = CompileRun("u8_b[1]");
2880 CHECK_EQ(0xFF, result->Int32Value());
2882 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2883 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2884 CHECK_EQ(0xBB, ab1_data[0]);
2885 CHECK_EQ(0xFF, ab1_data[1]);
2888 result = CompileRun("u8_a[0] + u8_a[1]");
2889 CHECK_EQ(0xDD, result->Int32Value());
2893 THREADED_TEST(SharedArrayBuffer_External) {
2894 i::FLAG_harmony_sharedarraybuffer = true;
2896 v8::Isolate* isolate = env->GetIsolate();
2897 v8::HandleScope handle_scope(isolate);
2899 i::ScopedVector<uint8_t> my_data(100);
2900 memset(my_data.start(), 0, 100);
2901 Local<v8::SharedArrayBuffer> ab3 =
2902 v8::SharedArrayBuffer::New(isolate, my_data.start(), 100);
2903 CheckInternalFieldsAreZero(ab3);
2904 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2905 CHECK(ab3->IsExternal());
2907 env->Global()->Set(v8_str("ab3"), ab3);
2909 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2910 CHECK_EQ(100, result->Int32Value());
2912 result = CompileRun(
2913 "var u8_b = new Uint8Array(ab3);"
2917 CHECK_EQ(100, result->Int32Value());
2918 CHECK_EQ(0xBB, my_data[0]);
2919 CHECK_EQ(0xCC, my_data[1]);
2922 result = CompileRun("u8_b[0] + u8_b[1]");
2923 CHECK_EQ(0xDD, result->Int32Value());
2927 THREADED_TEST(HiddenProperties) {
2929 v8::Isolate* isolate = env->GetIsolate();
2930 v8::HandleScope scope(isolate);
2932 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
2933 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2934 v8::Local<v8::String> empty = v8_str("");
2935 v8::Local<v8::String> prop_name = v8_str("prop_name");
2937 CcTest::heap()->CollectAllGarbage();
2939 // Make sure delete of a non-existent hidden value works
2940 CHECK(obj->DeleteHiddenValue(key));
2942 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
2943 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2944 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
2945 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2947 CcTest::heap()->CollectAllGarbage();
2949 // Make sure we do not find the hidden property.
2950 CHECK(!obj->Has(empty));
2951 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2952 CHECK(obj->Get(empty)->IsUndefined());
2953 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2954 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
2955 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2956 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2958 CcTest::heap()->CollectAllGarbage();
2960 // Add another property and delete it afterwards to force the object in
2962 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
2963 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2964 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2965 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2966 CHECK(obj->Delete(prop_name));
2967 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2969 CcTest::heap()->CollectAllGarbage();
2971 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2972 CHECK(obj->GetHiddenValue(key).IsEmpty());
2974 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
2975 CHECK(obj->DeleteHiddenValue(key));
2976 CHECK(obj->GetHiddenValue(key).IsEmpty());
2980 THREADED_TEST(Regress97784) {
2981 // Regression test for crbug.com/97784
2982 // Messing with the Object.prototype should not have effect on
2983 // hidden properties.
2985 v8::HandleScope scope(env->GetIsolate());
2987 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
2988 v8::Local<v8::String> key = v8_str("hidden");
2991 "set_called = false;"
2992 "Object.defineProperty("
2993 " Object.prototype,"
2995 " {get: function() { return 45; },"
2996 " set: function() { set_called = true; }})");
2998 CHECK(obj->GetHiddenValue(key).IsEmpty());
2999 // Make sure that the getter and setter from Object.prototype is not invoked.
3000 // If it did we would have full access to the hidden properties in
3002 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3003 ExpectFalse("set_called");
3004 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3008 THREADED_TEST(External) {
3009 v8::HandleScope scope(CcTest::isolate());
3011 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3013 env->Global()->Set(v8_str("ext"), ext);
3014 Local<Value> reext_obj = CompileRun("this.ext");
3015 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3016 int* ptr = static_cast<int*>(reext->Value());
3021 // Make sure unaligned pointers are wrapped properly.
3022 char* data = i::StrDup("0123456789");
3023 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3024 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3025 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3026 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3028 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3029 CHECK_EQ('0', *char_ptr);
3030 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3031 CHECK_EQ('1', *char_ptr);
3032 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3033 CHECK_EQ('2', *char_ptr);
3034 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3035 CHECK_EQ('3', *char_ptr);
3036 i::DeleteArray(data);
3040 THREADED_TEST(GlobalHandle) {
3041 v8::Isolate* isolate = CcTest::isolate();
3042 v8::Persistent<String> global;
3044 v8::HandleScope scope(isolate);
3045 global.Reset(isolate, v8_str("str"));
3048 v8::HandleScope scope(isolate);
3049 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3053 v8::HandleScope scope(isolate);
3054 global.Reset(isolate, v8_str("str"));
3057 v8::HandleScope scope(isolate);
3058 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3064 THREADED_TEST(ResettingGlobalHandle) {
3065 v8::Isolate* isolate = CcTest::isolate();
3066 v8::Persistent<String> global;
3068 v8::HandleScope scope(isolate);
3069 global.Reset(isolate, v8_str("str"));
3071 v8::internal::GlobalHandles* global_handles =
3072 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3073 int initial_handle_count = global_handles->global_handles_count();
3075 v8::HandleScope scope(isolate);
3076 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3079 v8::HandleScope scope(isolate);
3080 global.Reset(isolate, v8_str("longer"));
3082 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3084 v8::HandleScope scope(isolate);
3085 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3088 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3092 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3093 v8::Isolate* isolate = CcTest::isolate();
3094 v8::Persistent<String> global;
3096 v8::HandleScope scope(isolate);
3097 global.Reset(isolate, v8_str("str"));
3099 v8::internal::GlobalHandles* global_handles =
3100 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3101 int initial_handle_count = global_handles->global_handles_count();
3103 v8::HandleScope scope(isolate);
3104 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3107 v8::HandleScope scope(isolate);
3108 Local<String> empty;
3109 global.Reset(isolate, empty);
3111 CHECK(global.IsEmpty());
3112 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3117 static v8::Global<T> PassUnique(v8::Global<T> unique) {
3118 return unique.Pass();
3123 static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
3124 const v8::Persistent<T>& global) {
3125 v8::Global<String> unique(isolate, global);
3126 return unique.Pass();
3130 THREADED_TEST(Global) {
3131 v8::Isolate* isolate = CcTest::isolate();
3132 v8::Persistent<String> global;
3134 v8::HandleScope scope(isolate);
3135 global.Reset(isolate, v8_str("str"));
3137 v8::internal::GlobalHandles* global_handles =
3138 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3139 int initial_handle_count = global_handles->global_handles_count();
3141 v8::Global<String> unique(isolate, global);
3142 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3143 // Test assignment via Pass
3145 v8::Global<String> copy = unique.Pass();
3146 CHECK(unique.IsEmpty());
3147 CHECK(copy == global);
3148 CHECK_EQ(initial_handle_count + 1,
3149 global_handles->global_handles_count());
3150 unique = copy.Pass();
3152 // Test ctor via Pass
3154 v8::Global<String> copy(unique.Pass());
3155 CHECK(unique.IsEmpty());
3156 CHECK(copy == global);
3157 CHECK_EQ(initial_handle_count + 1,
3158 global_handles->global_handles_count());
3159 unique = copy.Pass();
3161 // Test pass through function call
3163 v8::Global<String> copy = PassUnique(unique.Pass());
3164 CHECK(unique.IsEmpty());
3165 CHECK(copy == global);
3166 CHECK_EQ(initial_handle_count + 1,
3167 global_handles->global_handles_count());
3168 unique = copy.Pass();
3170 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3172 // Test pass from function call
3174 v8::Global<String> unique = ReturnUnique(isolate, global);
3175 CHECK(unique == global);
3176 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3178 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3185 class TwoPassCallbackData;
3186 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
3187 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
3190 class TwoPassCallbackData {
3192 TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
3193 : first_pass_called_(false),
3194 second_pass_called_(false),
3196 instance_counter_(instance_counter) {
3197 HandleScope scope(isolate);
3198 i::ScopedVector<char> buffer(40);
3199 i::SNPrintF(buffer, "%p", static_cast<void*>(this));
3201 v8::String::NewFromUtf8(isolate, buffer.start(),
3202 v8::NewStringType::kNormal).ToLocalChecked();
3203 cell_.Reset(isolate, string);
3204 (*instance_counter_)++;
3207 ~TwoPassCallbackData() {
3208 CHECK(first_pass_called_);
3209 CHECK(second_pass_called_);
3210 CHECK(cell_.IsEmpty());
3211 (*instance_counter_)--;
3215 CHECK(!first_pass_called_);
3216 CHECK(!second_pass_called_);
3217 CHECK(!cell_.IsEmpty());
3219 first_pass_called_ = true;
3223 CHECK(first_pass_called_);
3224 CHECK(!second_pass_called_);
3225 CHECK(cell_.IsEmpty());
3226 second_pass_called_ = true;
3231 cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
3234 void MarkTriggerGc() { trigger_gc_ = true; }
3235 bool trigger_gc() { return trigger_gc_; }
3237 int* instance_counter() { return instance_counter_; }
3240 bool first_pass_called_;
3241 bool second_pass_called_;
3243 v8::Global<v8::String> cell_;
3244 int* instance_counter_;
3248 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
3249 ApiTestFuzzer::Fuzz();
3250 bool trigger_gc = data.GetParameter()->trigger_gc();
3251 int* instance_counter = data.GetParameter()->instance_counter();
3252 data.GetParameter()->SecondPass();
3253 if (!trigger_gc) return;
3254 auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
3256 CcTest::heap()->CollectAllGarbage();
3260 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
3261 data.GetParameter()->FirstPass();
3262 data.SetSecondPassCallback(SecondPassCallback);
3268 TEST(TwoPassPhantomCallbacks) {
3269 auto isolate = CcTest::isolate();
3270 const size_t kLength = 20;
3271 int instance_counter = 0;
3272 for (size_t i = 0; i < kLength; ++i) {
3273 auto data = new TwoPassCallbackData(isolate, &instance_counter);
3276 CHECK_EQ(static_cast<int>(kLength), instance_counter);
3277 CcTest::heap()->CollectAllGarbage();
3278 CHECK_EQ(0, instance_counter);
3282 TEST(TwoPassPhantomCallbacksNestedGc) {
3283 auto isolate = CcTest::isolate();
3284 const size_t kLength = 20;
3285 TwoPassCallbackData* array[kLength];
3286 int instance_counter = 0;
3287 for (size_t i = 0; i < kLength; ++i) {
3288 array[i] = new TwoPassCallbackData(isolate, &instance_counter);
3289 array[i]->SetWeak();
3291 array[5]->MarkTriggerGc();
3292 array[10]->MarkTriggerGc();
3293 array[15]->MarkTriggerGc();
3294 CHECK_EQ(static_cast<int>(kLength), instance_counter);
3295 CcTest::heap()->CollectAllGarbage();
3296 CHECK_EQ(0, instance_counter);
3302 void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
3305 Local<v8::Object> NewObjectForIntKey(
3306 v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
3308 auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
3309 auto obj = local->NewInstance();
3310 obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
3315 template <typename K, typename V>
3316 class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
3318 typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
3319 static const v8::PersistentContainerCallbackType kCallbackType =
3320 v8::kWeakWithInternalFields;
3321 struct WeakCallbackDataType {
3325 static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
3327 WeakCallbackDataType* data = new WeakCallbackDataType;
3332 static MapType* MapFromWeakCallbackInfo(
3333 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
3334 return data.GetParameter()->map;
3336 static K KeyFromWeakCallbackInfo(
3337 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
3338 return data.GetParameter()->key;
3340 static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
3341 static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
3342 CHECK_EQ(IntKeyToVoidPointer(key),
3343 v8::Object::GetAlignedPointerFromInternalField(value, 0));
3345 static void DisposeWeak(
3346 const v8::WeakCallbackInfo<WeakCallbackDataType>& info) {
3347 K key = KeyFromWeakCallbackInfo(info);
3348 CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
3349 DisposeCallbackData(info.GetParameter());
3354 template <typename Map>
3355 void TestGlobalValueMap() {
3357 v8::Isolate* isolate = env->GetIsolate();
3358 v8::Global<ObjectTemplate> templ;
3360 HandleScope scope(isolate);
3361 auto t = ObjectTemplate::New(isolate);
3362 t->SetInternalFieldCount(1);
3363 templ.Reset(isolate, t);
3366 v8::internal::GlobalHandles* global_handles =
3367 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3368 int initial_handle_count = global_handles->global_handles_count();
3369 CHECK_EQ(0, static_cast<int>(map.Size()));
3371 HandleScope scope(isolate);
3372 Local<v8::Object> obj = map.Get(7);
3373 CHECK(obj.IsEmpty());
3374 Local<v8::Object> expected = v8::Object::New(isolate);
3375 map.Set(7, expected);
3376 CHECK_EQ(1, static_cast<int>(map.Size()));
3378 CHECK(expected->Equals(obj));
3380 typename Map::PersistentValueReference ref = map.GetReference(7);
3381 CHECK(expected->Equals(ref.NewLocal(isolate)));
3383 v8::Global<v8::Object> removed = map.Remove(7);
3384 CHECK_EQ(0, static_cast<int>(map.Size()));
3385 CHECK(expected == removed);
3386 removed = map.Remove(7);
3387 CHECK(removed.IsEmpty());
3388 map.Set(8, expected);
3389 CHECK_EQ(1, static_cast<int>(map.Size()));
3390 map.Set(8, expected);
3391 CHECK_EQ(1, static_cast<int>(map.Size()));
3393 typename Map::PersistentValueReference ref;
3394 Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
3395 removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
3396 CHECK_EQ(1, static_cast<int>(map.Size()));
3397 CHECK(expected == removed);
3398 CHECK(expected2->Equals(ref.NewLocal(isolate)));
3401 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3403 CcTest::i_isolate()->heap()->CollectAllGarbage(
3404 i::Heap::kAbortIncrementalMarkingMask);
3408 CHECK_EQ(0, static_cast<int>(map.Size()));
3409 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3411 HandleScope scope(isolate);
3412 Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
3416 CHECK_EQ(0, static_cast<int>(map.Size()));
3417 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3423 TEST(GlobalValueMap) {
3424 // Default case, w/o weak callbacks:
3425 TestGlobalValueMap<v8::StdGlobalValueMap<int, v8::Object>>();
3427 // Custom traits with weak callbacks:
3428 typedef v8::GlobalValueMap<int, v8::Object,
3429 PhantomStdMapTraits<int, v8::Object>> WeakMap;
3430 TestGlobalValueMap<WeakMap>();
3434 TEST(PersistentValueVector) {
3436 v8::Isolate* isolate = env->GetIsolate();
3437 v8::internal::GlobalHandles* global_handles =
3438 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3439 int handle_count = global_handles->global_handles_count();
3440 HandleScope scope(isolate);
3442 v8::PersistentValueVector<v8::Object> vector(isolate);
3444 Local<v8::Object> obj1 = v8::Object::New(isolate);
3445 Local<v8::Object> obj2 = v8::Object::New(isolate);
3446 v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
3448 CHECK(vector.IsEmpty());
3449 CHECK_EQ(0, static_cast<int>(vector.Size()));
3451 vector.ReserveCapacity(3);
3452 CHECK(vector.IsEmpty());
3454 vector.Append(obj1);
3455 vector.Append(obj2);
3456 vector.Append(obj1);
3457 vector.Append(obj3.Pass());
3458 vector.Append(obj1);
3460 CHECK(!vector.IsEmpty());
3461 CHECK_EQ(5, static_cast<int>(vector.Size()));
3462 CHECK(obj3.IsEmpty());
3463 CHECK(obj1->Equals(vector.Get(0)));
3464 CHECK(obj1->Equals(vector.Get(2)));
3465 CHECK(obj1->Equals(vector.Get(4)));
3466 CHECK(obj2->Equals(vector.Get(1)));
3468 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3471 CHECK(vector.IsEmpty());
3472 CHECK_EQ(0, static_cast<int>(vector.Size()));
3473 CHECK_EQ(handle_count, global_handles->global_handles_count());
3477 THREADED_TEST(GlobalHandleUpcast) {
3478 v8::Isolate* isolate = CcTest::isolate();
3479 v8::HandleScope scope(isolate);
3480 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3481 v8::Persistent<String> global_string(isolate, local);
3482 v8::Persistent<Value>& global_value =
3483 v8::Persistent<Value>::Cast(global_string);
3484 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3485 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3486 global_string.Reset();
3490 THREADED_TEST(HandleEquality) {
3491 v8::Isolate* isolate = CcTest::isolate();
3492 v8::Persistent<String> global1;
3493 v8::Persistent<String> global2;
3495 v8::HandleScope scope(isolate);
3496 global1.Reset(isolate, v8_str("str"));
3497 global2.Reset(isolate, v8_str("str2"));
3499 CHECK_EQ(global1 == global1, true);
3500 CHECK_EQ(global1 != global1, false);
3502 v8::HandleScope scope(isolate);
3503 Local<String> local1 = Local<String>::New(isolate, global1);
3504 Local<String> local2 = Local<String>::New(isolate, global2);
3506 CHECK_EQ(global1 == local1, true);
3507 CHECK_EQ(global1 != local1, false);
3508 CHECK_EQ(local1 == global1, true);
3509 CHECK_EQ(local1 != global1, false);
3511 CHECK_EQ(global1 == local2, false);
3512 CHECK_EQ(global1 != local2, true);
3513 CHECK_EQ(local2 == global1, false);
3514 CHECK_EQ(local2 != global1, true);
3516 CHECK_EQ(local1 == local2, false);
3517 CHECK_EQ(local1 != local2, true);
3519 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3520 CHECK_EQ(local1 == anotherLocal1, true);
3521 CHECK_EQ(local1 != anotherLocal1, false);
3528 THREADED_TEST(LocalHandle) {
3529 v8::HandleScope scope(CcTest::isolate());
3530 v8::Local<String> local =
3531 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3532 CHECK_EQ(local->Length(), 3);
3536 class WeakCallCounter {
3538 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
3539 int id() { return id_; }
3540 void increment() { number_of_weak_calls_++; }
3541 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3545 int number_of_weak_calls_;
3549 template <typename T>
3550 struct WeakCallCounterAndPersistent {
3551 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3552 : counter(counter) {}
3553 WeakCallCounter* counter;
3554 v8::Persistent<T> handle;
3558 template <typename T>
3559 static void WeakPointerCallback(
3560 const v8::WeakCallbackInfo<WeakCallCounterAndPersistent<T>>& data) {
3561 CHECK_EQ(1234, data.GetParameter()->counter->id());
3562 data.GetParameter()->counter->increment();
3563 data.GetParameter()->handle.Reset();
3567 template <typename T>
3568 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3569 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3573 THREADED_TEST(ApiObjectGroups) {
3575 v8::Isolate* iso = env->GetIsolate();
3576 HandleScope scope(iso);
3578 WeakCallCounter counter(1234);
3580 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3581 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3582 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3583 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3584 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3585 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3588 HandleScope scope(iso);
3589 g1s1.handle.Reset(iso, Object::New(iso));
3590 g1s2.handle.Reset(iso, Object::New(iso));
3591 g1c1.handle.Reset(iso, Object::New(iso));
3592 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
3593 v8::WeakCallbackType::kParameter);
3594 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
3595 v8::WeakCallbackType::kParameter);
3596 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
3597 v8::WeakCallbackType::kParameter);
3599 g2s1.handle.Reset(iso, Object::New(iso));
3600 g2s2.handle.Reset(iso, Object::New(iso));
3601 g2c1.handle.Reset(iso, Object::New(iso));
3602 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
3603 v8::WeakCallbackType::kParameter);
3604 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
3605 v8::WeakCallbackType::kParameter);
3606 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
3607 v8::WeakCallbackType::kParameter);
3610 WeakCallCounterAndPersistent<Value> root(&counter);
3611 root.handle.Reset(iso, g1s1.handle); // make a root.
3613 // Connect group 1 and 2, make a cycle.
3615 HandleScope scope(iso);
3616 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())
3617 ->Set(0, Local<Value>::New(iso, g2s2.handle)));
3618 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())
3619 ->Set(0, Local<Value>::New(iso, g1s1.handle)));
3623 UniqueId id1 = MakeUniqueId(g1s1.handle);
3624 UniqueId id2 = MakeUniqueId(g2s2.handle);
3625 iso->SetObjectGroupId(g1s1.handle, id1);
3626 iso->SetObjectGroupId(g1s2.handle, id1);
3627 iso->SetReferenceFromGroup(id1, g1c1.handle);
3628 iso->SetObjectGroupId(g2s1.handle, id2);
3629 iso->SetObjectGroupId(g2s2.handle, id2);
3630 iso->SetReferenceFromGroup(id2, g2c1.handle);
3632 // Do a single full GC, ensure incremental marking is stopped.
3633 v8::internal::Heap* heap =
3634 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3635 heap->CollectAllGarbage();
3637 // All object should be alive.
3638 CHECK_EQ(0, counter.NumberOfWeakCalls());
3641 root.handle.SetWeak(&root, &WeakPointerCallback,
3642 v8::WeakCallbackType::kParameter);
3643 // But make children strong roots---all the objects (except for children)
3644 // should be collectable now.
3645 g1c1.handle.ClearWeak();
3646 g2c1.handle.ClearWeak();
3648 // Groups are deleted, rebuild groups.
3650 UniqueId id1 = MakeUniqueId(g1s1.handle);
3651 UniqueId id2 = MakeUniqueId(g2s2.handle);
3652 iso->SetObjectGroupId(g1s1.handle, id1);
3653 iso->SetObjectGroupId(g1s2.handle, id1);
3654 iso->SetReferenceFromGroup(id1, g1c1.handle);
3655 iso->SetObjectGroupId(g2s1.handle, id2);
3656 iso->SetObjectGroupId(g2s2.handle, id2);
3657 iso->SetReferenceFromGroup(id2, g2c1.handle);
3660 heap->CollectAllGarbage();
3662 // All objects should be gone. 5 global handles in total.
3663 CHECK_EQ(5, counter.NumberOfWeakCalls());
3665 // And now make children weak again and collect them.
3666 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
3667 v8::WeakCallbackType::kParameter);
3668 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
3669 v8::WeakCallbackType::kParameter);
3671 heap->CollectAllGarbage();
3672 CHECK_EQ(7, counter.NumberOfWeakCalls());
3676 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3678 v8::Isolate* iso = env->GetIsolate();
3679 HandleScope scope(iso);
3681 WeakCallCounter counter(1234);
3683 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3684 WeakCallCounterAndPersistent<String> g1s2(&counter);
3685 WeakCallCounterAndPersistent<String> g1c1(&counter);
3686 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3687 WeakCallCounterAndPersistent<String> g2s2(&counter);
3688 WeakCallCounterAndPersistent<String> g2c1(&counter);
3691 HandleScope scope(iso);
3692 g1s1.handle.Reset(iso, Object::New(iso));
3693 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3694 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3695 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
3696 v8::WeakCallbackType::kParameter);
3697 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
3698 v8::WeakCallbackType::kParameter);
3699 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
3700 v8::WeakCallbackType::kParameter);
3702 g2s1.handle.Reset(iso, Object::New(iso));
3703 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3704 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3705 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
3706 v8::WeakCallbackType::kParameter);
3707 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
3708 v8::WeakCallbackType::kParameter);
3709 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
3710 v8::WeakCallbackType::kParameter);
3713 WeakCallCounterAndPersistent<Value> root(&counter);
3714 root.handle.Reset(iso, g1s1.handle); // make a root.
3716 // Connect group 1 and 2, make a cycle.
3718 HandleScope scope(iso);
3719 CHECK(Local<Object>::New(iso, g1s1.handle)
3720 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3721 CHECK(Local<Object>::New(iso, g2s1.handle)
3722 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3726 UniqueId id1 = MakeUniqueId(g1s1.handle);
3727 UniqueId id2 = MakeUniqueId(g2s2.handle);
3728 iso->SetObjectGroupId(g1s1.handle, id1);
3729 iso->SetObjectGroupId(g1s2.handle, id1);
3730 iso->SetReference(g1s1.handle, g1c1.handle);
3731 iso->SetObjectGroupId(g2s1.handle, id2);
3732 iso->SetObjectGroupId(g2s2.handle, id2);
3733 iso->SetReferenceFromGroup(id2, g2c1.handle);
3735 // Do a single full GC, ensure incremental marking is stopped.
3736 v8::internal::Heap* heap =
3737 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3738 heap->CollectAllGarbage();
3740 // All object should be alive.
3741 CHECK_EQ(0, counter.NumberOfWeakCalls());
3744 root.handle.SetWeak(&root, &WeakPointerCallback,
3745 v8::WeakCallbackType::kParameter);
3746 // But make children strong roots---all the objects (except for children)
3747 // should be collectable now.
3748 g1c1.handle.ClearWeak();
3749 g2c1.handle.ClearWeak();
3751 // Groups are deleted, rebuild groups.
3753 UniqueId id1 = MakeUniqueId(g1s1.handle);
3754 UniqueId id2 = MakeUniqueId(g2s2.handle);
3755 iso->SetObjectGroupId(g1s1.handle, id1);
3756 iso->SetObjectGroupId(g1s2.handle, id1);
3757 iso->SetReference(g1s1.handle, g1c1.handle);
3758 iso->SetObjectGroupId(g2s1.handle, id2);
3759 iso->SetObjectGroupId(g2s2.handle, id2);
3760 iso->SetReferenceFromGroup(id2, g2c1.handle);
3763 heap->CollectAllGarbage();
3765 // All objects should be gone. 5 global handles in total.
3766 CHECK_EQ(5, counter.NumberOfWeakCalls());
3768 // And now make children weak again and collect them.
3769 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback,
3770 v8::WeakCallbackType::kParameter);
3771 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback,
3772 v8::WeakCallbackType::kParameter);
3774 heap->CollectAllGarbage();
3775 CHECK_EQ(7, counter.NumberOfWeakCalls());
3779 THREADED_TEST(ApiObjectGroupsCycle) {
3781 v8::Isolate* iso = env->GetIsolate();
3782 HandleScope scope(iso);
3784 WeakCallCounter counter(1234);
3786 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3787 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3788 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3789 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3790 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3791 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3792 WeakCallCounterAndPersistent<Value> g4s1(&counter);
3793 WeakCallCounterAndPersistent<Value> g4s2(&counter);
3796 HandleScope scope(iso);
3797 g1s1.handle.Reset(iso, Object::New(iso));
3798 g1s2.handle.Reset(iso, Object::New(iso));
3799 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
3800 v8::WeakCallbackType::kParameter);
3801 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
3802 v8::WeakCallbackType::kParameter);
3803 CHECK(g1s1.handle.IsWeak());
3804 CHECK(g1s2.handle.IsWeak());
3806 g2s1.handle.Reset(iso, Object::New(iso));
3807 g2s2.handle.Reset(iso, Object::New(iso));
3808 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
3809 v8::WeakCallbackType::kParameter);
3810 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
3811 v8::WeakCallbackType::kParameter);
3812 CHECK(g2s1.handle.IsWeak());
3813 CHECK(g2s2.handle.IsWeak());
3815 g3s1.handle.Reset(iso, Object::New(iso));
3816 g3s2.handle.Reset(iso, Object::New(iso));
3817 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback,
3818 v8::WeakCallbackType::kParameter);
3819 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback,
3820 v8::WeakCallbackType::kParameter);
3821 CHECK(g3s1.handle.IsWeak());
3822 CHECK(g3s2.handle.IsWeak());
3824 g4s1.handle.Reset(iso, Object::New(iso));
3825 g4s2.handle.Reset(iso, Object::New(iso));
3826 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback,
3827 v8::WeakCallbackType::kParameter);
3828 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback,
3829 v8::WeakCallbackType::kParameter);
3830 CHECK(g4s1.handle.IsWeak());
3831 CHECK(g4s2.handle.IsWeak());
3834 WeakCallCounterAndPersistent<Value> root(&counter);
3835 root.handle.Reset(iso, g1s1.handle); // make a root.
3837 // Connect groups. We're building the following cycle:
3838 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3841 UniqueId id1 = MakeUniqueId(g1s1.handle);
3842 UniqueId id2 = MakeUniqueId(g2s1.handle);
3843 UniqueId id3 = MakeUniqueId(g3s1.handle);
3844 UniqueId id4 = MakeUniqueId(g4s1.handle);
3845 iso->SetObjectGroupId(g1s1.handle, id1);
3846 iso->SetObjectGroupId(g1s2.handle, id1);
3847 iso->SetReferenceFromGroup(id1, g2s1.handle);
3848 iso->SetObjectGroupId(g2s1.handle, id2);
3849 iso->SetObjectGroupId(g2s2.handle, id2);
3850 iso->SetReferenceFromGroup(id2, g3s1.handle);
3851 iso->SetObjectGroupId(g3s1.handle, id3);
3852 iso->SetObjectGroupId(g3s2.handle, id3);
3853 iso->SetReferenceFromGroup(id3, g4s1.handle);
3854 iso->SetObjectGroupId(g4s1.handle, id4);
3855 iso->SetObjectGroupId(g4s2.handle, id4);
3856 iso->SetReferenceFromGroup(id4, g1s1.handle);
3858 // Do a single full GC
3859 v8::internal::Heap* heap =
3860 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3861 heap->CollectAllGarbage();
3863 // All object should be alive.
3864 CHECK_EQ(0, counter.NumberOfWeakCalls());
3867 root.handle.SetWeak(&root, &WeakPointerCallback,
3868 v8::WeakCallbackType::kParameter);
3870 // Groups are deleted, rebuild groups.
3872 UniqueId id1 = MakeUniqueId(g1s1.handle);
3873 UniqueId id2 = MakeUniqueId(g2s1.handle);
3874 UniqueId id3 = MakeUniqueId(g3s1.handle);
3875 UniqueId id4 = MakeUniqueId(g4s1.handle);
3876 iso->SetObjectGroupId(g1s1.handle, id1);
3877 iso->SetObjectGroupId(g1s2.handle, id1);
3878 iso->SetReferenceFromGroup(id1, g2s1.handle);
3879 iso->SetObjectGroupId(g2s1.handle, id2);
3880 iso->SetObjectGroupId(g2s2.handle, id2);
3881 iso->SetReferenceFromGroup(id2, g3s1.handle);
3882 iso->SetObjectGroupId(g3s1.handle, id3);
3883 iso->SetObjectGroupId(g3s2.handle, id3);
3884 iso->SetReferenceFromGroup(id3, g4s1.handle);
3885 iso->SetObjectGroupId(g4s1.handle, id4);
3886 iso->SetObjectGroupId(g4s2.handle, id4);
3887 iso->SetReferenceFromGroup(id4, g1s1.handle);
3890 heap->CollectAllGarbage();
3892 // All objects should be gone. 9 global handles in total.
3893 CHECK_EQ(9, counter.NumberOfWeakCalls());
3897 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3898 // on the buildbots, so was made non-threaded for the time being.
3899 TEST(ApiObjectGroupsCycleForScavenger) {
3900 i::FLAG_stress_compaction = false;
3901 i::FLAG_gc_global = false;
3903 v8::Isolate* iso = env->GetIsolate();
3904 HandleScope scope(iso);
3906 WeakCallCounter counter(1234);
3908 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3909 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3910 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3911 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3912 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3913 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3916 HandleScope scope(iso);
3917 g1s1.handle.Reset(iso, Object::New(iso));
3918 g1s2.handle.Reset(iso, Object::New(iso));
3919 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback,
3920 v8::WeakCallbackType::kParameter);
3921 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback,
3922 v8::WeakCallbackType::kParameter);
3924 g2s1.handle.Reset(iso, Object::New(iso));
3925 g2s2.handle.Reset(iso, Object::New(iso));
3926 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback,
3927 v8::WeakCallbackType::kParameter);
3928 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback,
3929 v8::WeakCallbackType::kParameter);
3931 g3s1.handle.Reset(iso, Object::New(iso));
3932 g3s2.handle.Reset(iso, Object::New(iso));
3933 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback,
3934 v8::WeakCallbackType::kParameter);
3935 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback,
3936 v8::WeakCallbackType::kParameter);
3940 WeakCallCounterAndPersistent<Value> root(&counter);
3941 root.handle.Reset(iso, g1s1.handle);
3942 root.handle.MarkPartiallyDependent();
3944 // Connect groups. We're building the following cycle:
3945 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3948 HandleScope handle_scope(iso);
3949 g1s1.handle.MarkPartiallyDependent();
3950 g1s2.handle.MarkPartiallyDependent();
3951 g2s1.handle.MarkPartiallyDependent();
3952 g2s2.handle.MarkPartiallyDependent();
3953 g3s1.handle.MarkPartiallyDependent();
3954 g3s2.handle.MarkPartiallyDependent();
3955 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3956 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3957 Local<Object>::New(iso, g1s1.handle.As<Object>())
3958 ->Set(v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3959 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3960 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3961 Local<Object>::New(iso, g2s1.handle.As<Object>())
3962 ->Set(v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3963 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3964 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3965 Local<Object>::New(iso, g3s1.handle.As<Object>())
3966 ->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3969 v8::internal::Heap* heap =
3970 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3971 heap->CollectAllGarbage();
3973 // All objects should be alive.
3974 CHECK_EQ(0, counter.NumberOfWeakCalls());
3977 root.handle.SetWeak(&root, &WeakPointerCallback,
3978 v8::WeakCallbackType::kParameter);
3979 root.handle.MarkPartiallyDependent();
3981 // Groups are deleted, rebuild groups.
3983 HandleScope handle_scope(iso);
3984 g1s1.handle.MarkPartiallyDependent();
3985 g1s2.handle.MarkPartiallyDependent();
3986 g2s1.handle.MarkPartiallyDependent();
3987 g2s2.handle.MarkPartiallyDependent();
3988 g3s1.handle.MarkPartiallyDependent();
3989 g3s2.handle.MarkPartiallyDependent();
3990 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3991 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3992 Local<Object>::New(iso, g1s1.handle.As<Object>())
3993 ->Set(v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3994 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3995 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3996 Local<Object>::New(iso, g2s1.handle.As<Object>())
3997 ->Set(v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3998 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3999 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4000 Local<Object>::New(iso, g3s1.handle.As<Object>())
4001 ->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4004 heap->CollectAllGarbage();
4006 // All objects should be gone. 7 global handles in total.
4007 CHECK_EQ(7, counter.NumberOfWeakCalls());
4011 THREADED_TEST(ScriptException) {
4013 v8::HandleScope scope(env->GetIsolate());
4014 Local<Script> script = v8_compile("throw 'panama!';");
4015 v8::TryCatch try_catch(env->GetIsolate());
4016 Local<Value> result = script->Run();
4017 CHECK(result.IsEmpty());
4018 CHECK(try_catch.HasCaught());
4019 String::Utf8Value exception_value(try_catch.Exception());
4020 CHECK_EQ(0, strcmp(*exception_value, "panama!"));
4024 TEST(TryCatchCustomException) {
4026 v8::Isolate* isolate = env->GetIsolate();
4027 v8::HandleScope scope(isolate);
4028 v8::TryCatch try_catch(isolate);
4030 "function CustomError() { this.a = 'b'; }"
4031 "(function f() { throw new CustomError(); })();");
4032 CHECK(try_catch.HasCaught());
4033 CHECK(try_catch.Exception()
4036 ->Equals(v8_str("b")));
4040 bool message_received;
4043 static void check_message_0(v8::Handle<v8::Message> message,
4044 v8::Handle<Value> data) {
4045 CHECK_EQ(5.76, data->NumberValue());
4046 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4047 CHECK(!message->IsSharedCrossOrigin());
4048 message_received = true;
4052 THREADED_TEST(MessageHandler0) {
4053 message_received = false;
4054 v8::HandleScope scope(CcTest::isolate());
4055 CHECK(!message_received);
4056 LocalContext context;
4057 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4058 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4060 CHECK(message_received);
4061 // clear out the message listener
4062 v8::V8::RemoveMessageListeners(check_message_0);
4066 static void check_message_1(v8::Handle<v8::Message> message,
4067 v8::Handle<Value> data) {
4068 CHECK(data->IsNumber());
4069 CHECK_EQ(1337, data->Int32Value());
4070 CHECK(!message->IsSharedCrossOrigin());
4071 message_received = true;
4075 TEST(MessageHandler1) {
4076 message_received = false;
4077 v8::HandleScope scope(CcTest::isolate());
4078 CHECK(!message_received);
4079 v8::V8::AddMessageListener(check_message_1);
4080 LocalContext context;
4081 CompileRun("throw 1337;");
4082 CHECK(message_received);
4083 // clear out the message listener
4084 v8::V8::RemoveMessageListeners(check_message_1);
4088 static void check_message_2(v8::Handle<v8::Message> message,
4089 v8::Handle<Value> data) {
4090 LocalContext context;
4091 CHECK(data->IsObject());
4092 v8::Local<v8::Value> hidden_property =
4093 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4094 CHECK(v8_str("hidden value")->Equals(hidden_property));
4095 CHECK(!message->IsSharedCrossOrigin());
4096 message_received = true;
4100 TEST(MessageHandler2) {
4101 message_received = false;
4102 v8::HandleScope scope(CcTest::isolate());
4103 CHECK(!message_received);
4104 v8::V8::AddMessageListener(check_message_2);
4105 LocalContext context;
4106 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4107 v8::Object::Cast(*error)
4108 ->SetHiddenValue(v8_str("hidden key"), v8_str("hidden value"));
4109 context->Global()->Set(v8_str("error"), error);
4110 CompileRun("throw error;");
4111 CHECK(message_received);
4112 // clear out the message listener
4113 v8::V8::RemoveMessageListeners(check_message_2);
4117 static void check_message_3(v8::Handle<v8::Message> message,
4118 v8::Handle<Value> data) {
4119 CHECK(message->IsSharedCrossOrigin());
4120 CHECK(message->GetScriptOrigin().Options().IsSharedCrossOrigin());
4121 CHECK(message->GetScriptOrigin().Options().IsEmbedderDebugScript());
4122 CHECK(message->GetScriptOrigin().Options().IsOpaque());
4123 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4124 CHECK_EQ(7.40, message->GetScriptOrigin().SourceMapUrl()->NumberValue());
4125 message_received = true;
4129 TEST(MessageHandler3) {
4130 message_received = false;
4131 v8::Isolate* isolate = CcTest::isolate();
4132 v8::HandleScope scope(isolate);
4133 CHECK(!message_received);
4134 v8::V8::AddMessageListener(check_message_3);
4135 LocalContext context;
4136 v8::ScriptOrigin origin = v8::ScriptOrigin(
4137 v8_str("6.75"), v8::Integer::New(isolate, 1),
4138 v8::Integer::New(isolate, 2), v8::True(isolate), Handle<v8::Integer>(),
4139 v8::True(isolate), v8_str("7.40"), v8::True(isolate));
4140 v8::Handle<v8::Script> script =
4141 Script::Compile(v8_str("throw 'error'"), &origin);
4143 CHECK(message_received);
4144 // clear out the message listener
4145 v8::V8::RemoveMessageListeners(check_message_3);
4149 static void check_message_4(v8::Handle<v8::Message> message,
4150 v8::Handle<Value> data) {
4151 CHECK(!message->IsSharedCrossOrigin());
4152 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4153 message_received = true;
4157 TEST(MessageHandler4) {
4158 message_received = false;
4159 v8::Isolate* isolate = CcTest::isolate();
4160 v8::HandleScope scope(isolate);
4161 CHECK(!message_received);
4162 v8::V8::AddMessageListener(check_message_4);
4163 LocalContext context;
4164 v8::ScriptOrigin origin =
4165 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4166 v8::Integer::New(isolate, 2), v8::False(isolate));
4167 v8::Handle<v8::Script> script =
4168 Script::Compile(v8_str("throw 'error'"), &origin);
4170 CHECK(message_received);
4171 // clear out the message listener
4172 v8::V8::RemoveMessageListeners(check_message_4);
4176 static void check_message_5a(v8::Handle<v8::Message> message,
4177 v8::Handle<Value> data) {
4178 CHECK(message->IsSharedCrossOrigin());
4179 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4180 message_received = true;
4184 static void check_message_5b(v8::Handle<v8::Message> message,
4185 v8::Handle<Value> data) {
4186 CHECK(!message->IsSharedCrossOrigin());
4187 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4188 message_received = true;
4192 TEST(MessageHandler5) {
4193 message_received = false;
4194 v8::Isolate* isolate = CcTest::isolate();
4195 v8::HandleScope scope(isolate);
4196 CHECK(!message_received);
4197 v8::V8::AddMessageListener(check_message_5a);
4198 LocalContext context;
4199 v8::ScriptOrigin origin1 =
4200 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4201 v8::Integer::New(isolate, 2), v8::True(isolate));
4202 v8::Handle<v8::Script> script =
4203 Script::Compile(v8_str("throw 'error'"), &origin1);
4205 CHECK(message_received);
4206 // clear out the message listener
4207 v8::V8::RemoveMessageListeners(check_message_5a);
4209 message_received = false;
4210 v8::V8::AddMessageListener(check_message_5b);
4211 v8::ScriptOrigin origin2 =
4212 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4213 v8::Integer::New(isolate, 2), v8::False(isolate));
4214 script = Script::Compile(v8_str("throw 'error'"), &origin2);
4216 CHECK(message_received);
4217 // clear out the message listener
4218 v8::V8::RemoveMessageListeners(check_message_5b);
4222 TEST(NativeWeakMap) {
4223 v8::Isolate* isolate = CcTest::isolate();
4224 HandleScope scope(isolate);
4225 Local<v8::NativeWeakMap> weak_map(v8::NativeWeakMap::New(isolate));
4226 CHECK(!weak_map.IsEmpty());
4229 Local<Object> value = v8::Object::New(isolate);
4231 Local<Object> local1 = v8::Object::New(isolate);
4232 CHECK(!weak_map->Has(local1));
4233 CHECK(weak_map->Get(local1)->IsUndefined());
4234 weak_map->Set(local1, value);
4235 CHECK(weak_map->Has(local1));
4236 CHECK(value->Equals(weak_map->Get(local1)));
4238 WeakCallCounter counter(1234);
4239 WeakCallCounterAndPersistent<Value> o1(&counter);
4240 WeakCallCounterAndPersistent<Value> o2(&counter);
4241 WeakCallCounterAndPersistent<Value> s1(&counter);
4243 HandleScope scope(isolate);
4244 Local<v8::Object> obj1 = v8::Object::New(isolate);
4245 Local<v8::Object> obj2 = v8::Object::New(isolate);
4246 Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
4248 weak_map->Set(obj1, value);
4249 weak_map->Set(obj2, value);
4250 weak_map->Set(sym1, value);
4252 o1.handle.Reset(isolate, obj1);
4253 o2.handle.Reset(isolate, obj2);
4254 s1.handle.Reset(isolate, sym1);
4256 CHECK(weak_map->Has(local1));
4257 CHECK(weak_map->Has(obj1));
4258 CHECK(weak_map->Has(obj2));
4259 CHECK(weak_map->Has(sym1));
4261 CHECK(value->Equals(weak_map->Get(local1)));
4262 CHECK(value->Equals(weak_map->Get(obj1)));
4263 CHECK(value->Equals(weak_map->Get(obj2)));
4264 CHECK(value->Equals(weak_map->Get(sym1)));
4266 CcTest::heap()->CollectAllGarbage();
4268 HandleScope scope(isolate);
4269 CHECK(value->Equals(weak_map->Get(local1)));
4270 CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, o1.handle))));
4271 CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, o2.handle))));
4272 CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, s1.handle))));
4275 o1.handle.SetWeak(&o1, &WeakPointerCallback,
4276 v8::WeakCallbackType::kParameter);
4277 o2.handle.SetWeak(&o2, &WeakPointerCallback,
4278 v8::WeakCallbackType::kParameter);
4279 s1.handle.SetWeak(&s1, &WeakPointerCallback,
4280 v8::WeakCallbackType::kParameter);
4282 CcTest::heap()->CollectAllGarbage();
4283 CHECK_EQ(3, counter.NumberOfWeakCalls());
4285 CHECK(o1.handle.IsEmpty());
4286 CHECK(o2.handle.IsEmpty());
4287 CHECK(s1.handle.IsEmpty());
4289 CHECK(value->Equals(weak_map->Get(local1)));
4290 CHECK(weak_map->Delete(local1));
4291 CHECK(!weak_map->Has(local1));
4292 CHECK(weak_map->Get(local1)->IsUndefined());
4296 THREADED_TEST(GetSetProperty) {
4297 LocalContext context;
4298 v8::Isolate* isolate = context->GetIsolate();
4299 v8::HandleScope scope(isolate);
4300 context->Global()->Set(v8_str("foo"), v8_num(14));
4301 context->Global()->Set(v8_str("12"), v8_num(92));
4302 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4303 context->Global()->Set(v8_num(13), v8_num(56));
4304 Local<Value> foo = CompileRun("this.foo");
4305 CHECK_EQ(14, foo->Int32Value());
4306 Local<Value> twelve = CompileRun("this[12]");
4307 CHECK_EQ(92, twelve->Int32Value());
4308 Local<Value> sixteen = CompileRun("this[16]");
4309 CHECK_EQ(32, sixteen->Int32Value());
4310 Local<Value> thirteen = CompileRun("this[13]");
4311 CHECK_EQ(56, thirteen->Int32Value());
4313 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4314 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4315 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4317 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4318 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4319 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4321 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4322 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4323 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4327 THREADED_TEST(PropertyAttributes) {
4328 LocalContext context;
4329 v8::HandleScope scope(context->GetIsolate());
4331 Local<String> prop = v8_str("none");
4332 context->Global()->Set(prop, v8_num(7));
4333 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4335 prop = v8_str("read_only");
4336 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4337 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4338 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4339 CompileRun("read_only = 9");
4340 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4341 context->Global()->Set(prop, v8_num(10));
4342 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4344 prop = v8_str("dont_delete");
4345 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4346 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4347 CompileRun("delete dont_delete");
4348 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4349 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4351 prop = v8_str("dont_enum");
4352 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4353 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4355 prop = v8_str("absent");
4356 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4357 Local<Value> fake_prop = v8_num(1);
4358 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4360 TryCatch try_catch(context->GetIsolate());
4361 Local<Value> exception =
4362 CompileRun("({ toString: function() { throw 'exception';} })");
4363 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4364 CHECK(try_catch.HasCaught());
4365 String::Utf8Value exception_value(try_catch.Exception());
4366 CHECK_EQ(0, strcmp("exception", *exception_value));
4371 THREADED_TEST(Array) {
4372 LocalContext context;
4373 v8::HandleScope scope(context->GetIsolate());
4374 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4375 CHECK_EQ(0u, array->Length());
4376 CHECK(array->Get(0)->IsUndefined());
4377 CHECK(!array->Has(0));
4378 CHECK(array->Get(100)->IsUndefined());
4379 CHECK(!array->Has(100));
4380 array->Set(2, v8_num(7));
4381 CHECK_EQ(3u, array->Length());
4382 CHECK(!array->Has(0));
4383 CHECK(!array->Has(1));
4384 CHECK(array->Has(2));
4385 CHECK_EQ(7, array->Get(2)->Int32Value());
4386 Local<Value> obj = CompileRun("[1, 2, 3]");
4387 Local<v8::Array> arr = obj.As<v8::Array>();
4388 CHECK_EQ(3u, arr->Length());
4389 CHECK_EQ(1, arr->Get(0)->Int32Value());
4390 CHECK_EQ(2, arr->Get(1)->Int32Value());
4391 CHECK_EQ(3, arr->Get(2)->Int32Value());
4392 array = v8::Array::New(context->GetIsolate(), 27);
4393 CHECK_EQ(27u, array->Length());
4394 array = v8::Array::New(context->GetIsolate(), -27);
4395 CHECK_EQ(0u, array->Length());
4399 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4400 v8::EscapableHandleScope scope(args.GetIsolate());
4401 ApiTestFuzzer::Fuzz();
4402 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4403 for (int i = 0; i < args.Length(); i++) result->Set(i, args[i]);
4404 args.GetReturnValue().Set(scope.Escape(result));
4408 THREADED_TEST(Vector) {
4409 v8::Isolate* isolate = CcTest::isolate();
4410 v8::HandleScope scope(isolate);
4411 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4412 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4413 LocalContext context(0, global);
4415 const char* fun = "f()";
4416 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4417 CHECK_EQ(0u, a0->Length());
4419 const char* fun2 = "f(11)";
4420 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4421 CHECK_EQ(1u, a1->Length());
4422 CHECK_EQ(11, a1->Get(0)->Int32Value());
4424 const char* fun3 = "f(12, 13)";
4425 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4426 CHECK_EQ(2u, a2->Length());
4427 CHECK_EQ(12, a2->Get(0)->Int32Value());
4428 CHECK_EQ(13, a2->Get(1)->Int32Value());
4430 const char* fun4 = "f(14, 15, 16)";
4431 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4432 CHECK_EQ(3u, a3->Length());
4433 CHECK_EQ(14, a3->Get(0)->Int32Value());
4434 CHECK_EQ(15, a3->Get(1)->Int32Value());
4435 CHECK_EQ(16, a3->Get(2)->Int32Value());
4437 const char* fun5 = "f(17, 18, 19, 20)";
4438 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4439 CHECK_EQ(4u, a4->Length());
4440 CHECK_EQ(17, a4->Get(0)->Int32Value());
4441 CHECK_EQ(18, a4->Get(1)->Int32Value());
4442 CHECK_EQ(19, a4->Get(2)->Int32Value());
4443 CHECK_EQ(20, a4->Get(3)->Int32Value());
4447 THREADED_TEST(FunctionCall) {
4448 LocalContext context;
4449 v8::Isolate* isolate = context->GetIsolate();
4450 v8::HandleScope scope(isolate);
4454 " for (var i = 0; i < arguments.length; i++) {"
4455 " result.push(arguments[i]);"
4459 "function ReturnThisSloppy() {"
4462 "function ReturnThisStrict() {"
4466 Local<Function> Foo =
4467 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4468 Local<Function> ReturnThisSloppy =
4469 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4470 Local<Function> ReturnThisStrict =
4471 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4473 v8::Handle<Value>* args0 = NULL;
4474 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4475 CHECK_EQ(0u, a0->Length());
4477 v8::Handle<Value> args1[] = {v8_num(1.1)};
4478 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4479 CHECK_EQ(1u, a1->Length());
4480 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4482 v8::Handle<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
4483 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4484 CHECK_EQ(2u, a2->Length());
4485 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4486 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4488 v8::Handle<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
4489 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4490 CHECK_EQ(3u, a3->Length());
4491 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4492 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4493 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4495 v8::Handle<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
4497 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4498 CHECK_EQ(4u, a4->Length());
4499 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4500 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4501 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4502 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4504 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4505 CHECK(r1->StrictEquals(context->Global()));
4506 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4507 CHECK(r2->StrictEquals(context->Global()));
4508 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4509 CHECK(r3->IsNumberObject());
4510 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4511 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4512 CHECK(r4->IsStringObject());
4513 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4514 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4515 CHECK(r5->IsBooleanObject());
4516 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4518 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4519 CHECK(r6->IsUndefined());
4520 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4521 CHECK(r7->IsNull());
4522 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4523 CHECK(r8->StrictEquals(v8_num(42)));
4524 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4525 CHECK(r9->StrictEquals(v8_str("hello")));
4526 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4527 CHECK(r10->StrictEquals(v8::True(isolate)));
4531 THREADED_TEST(ConstructCall) {
4532 LocalContext context;
4533 v8::Isolate* isolate = context->GetIsolate();
4534 v8::HandleScope scope(isolate);
4538 " for (var i = 0; i < arguments.length; i++) {"
4539 " result.push(arguments[i]);"
4543 Local<Function> Foo =
4544 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4546 v8::Handle<Value>* args0 = NULL;
4547 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4548 CHECK_EQ(0u, a0->Length());
4550 v8::Handle<Value> args1[] = {v8_num(1.1)};
4551 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4552 CHECK_EQ(1u, a1->Length());
4553 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4555 v8::Handle<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
4556 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4557 CHECK_EQ(2u, a2->Length());
4558 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4559 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4561 v8::Handle<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
4562 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4563 CHECK_EQ(3u, a3->Length());
4564 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4565 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4566 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4568 v8::Handle<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
4570 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4571 CHECK_EQ(4u, a4->Length());
4572 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4573 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4574 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4575 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4579 static void CheckUncle(v8::TryCatch* try_catch) {
4580 CHECK(try_catch->HasCaught());
4581 String::Utf8Value str_value(try_catch->Exception());
4582 CHECK_EQ(0, strcmp(*str_value, "uncle?"));
4587 THREADED_TEST(ConversionNumber) {
4589 v8::Isolate* isolate = env->GetIsolate();
4590 v8::HandleScope scope(isolate);
4591 // Very large number.
4592 CompileRun("var obj = Math.pow(2,32) * 1237;");
4593 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4594 CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
4595 CHECK_EQ(0, obj->ToInt32(isolate)->Value());
4597 obj->ToUint32(isolate)->Value()); // NOLINT - no CHECK_EQ for unsigned.
4599 CompileRun("var obj = -1234567890123;");
4600 obj = env->Global()->Get(v8_str("obj"));
4601 CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
4602 CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
4603 CHECK(2382691125u == obj->ToUint32(isolate)->Value()); // NOLINT
4604 // Small positive integer.
4605 CompileRun("var obj = 42;");
4606 obj = env->Global()->Get(v8_str("obj"));
4607 CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
4608 CHECK_EQ(42, obj->ToInt32(isolate)->Value());
4609 CHECK(42u == obj->ToUint32(isolate)->Value()); // NOLINT
4610 // Negative integer.
4611 CompileRun("var obj = -37;");
4612 obj = env->Global()->Get(v8_str("obj"));
4613 CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
4614 CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
4615 CHECK(4294967259u == obj->ToUint32(isolate)->Value()); // NOLINT
4616 // Positive non-int32 integer.
4617 CompileRun("var obj = 0x81234567;");
4618 obj = env->Global()->Get(v8_str("obj"));
4619 CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
4620 CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
4621 CHECK(2166572391u == obj->ToUint32(isolate)->Value()); // NOLINT
4623 CompileRun("var obj = 42.3;");
4624 obj = env->Global()->Get(v8_str("obj"));
4625 CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
4626 CHECK_EQ(42, obj->ToInt32(isolate)->Value());
4627 CHECK(42u == obj->ToUint32(isolate)->Value()); // NOLINT
4628 // Large negative fraction.
4629 CompileRun("var obj = -5726623061.75;");
4630 obj = env->Global()->Get(v8_str("obj"));
4631 CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
4632 CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
4633 CHECK(2863311531u == obj->ToUint32(isolate)->Value()); // NOLINT
4637 THREADED_TEST(isNumberType) {
4639 v8::HandleScope scope(env->GetIsolate());
4640 // Very large number.
4641 CompileRun("var obj = Math.pow(2,32) * 1237;");
4642 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4643 CHECK(!obj->IsInt32());
4644 CHECK(!obj->IsUint32());
4645 // Large negative number.
4646 CompileRun("var obj = -1234567890123;");
4647 obj = env->Global()->Get(v8_str("obj"));
4648 CHECK(!obj->IsInt32());
4649 CHECK(!obj->IsUint32());
4650 // Small positive integer.
4651 CompileRun("var obj = 42;");
4652 obj = env->Global()->Get(v8_str("obj"));
4653 CHECK(obj->IsInt32());
4654 CHECK(obj->IsUint32());
4655 // Negative integer.
4656 CompileRun("var obj = -37;");
4657 obj = env->Global()->Get(v8_str("obj"));
4658 CHECK(obj->IsInt32());
4659 CHECK(!obj->IsUint32());
4660 // Positive non-int32 integer.
4661 CompileRun("var obj = 0x81234567;");
4662 obj = env->Global()->Get(v8_str("obj"));
4663 CHECK(!obj->IsInt32());
4664 CHECK(obj->IsUint32());
4666 CompileRun("var obj = 42.3;");
4667 obj = env->Global()->Get(v8_str("obj"));
4668 CHECK(!obj->IsInt32());
4669 CHECK(!obj->IsUint32());
4670 // Large negative fraction.
4671 CompileRun("var obj = -5726623061.75;");
4672 obj = env->Global()->Get(v8_str("obj"));
4673 CHECK(!obj->IsInt32());
4674 CHECK(!obj->IsUint32());
4676 CompileRun("var obj = 0.0;");
4677 obj = env->Global()->Get(v8_str("obj"));
4678 CHECK(obj->IsInt32());
4679 CHECK(obj->IsUint32());
4681 CompileRun("var obj = -0.0;");
4682 obj = env->Global()->Get(v8_str("obj"));
4683 CHECK(!obj->IsInt32());
4684 CHECK(!obj->IsUint32());
4688 THREADED_TEST(ConversionException) {
4690 v8::Isolate* isolate = env->GetIsolate();
4691 v8::HandleScope scope(isolate);
4693 "function TestClass() { };"
4694 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4695 "var obj = new TestClass();");
4696 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4698 v8::TryCatch try_catch(isolate);
4700 Local<Value> to_string_result = obj->ToString(isolate);
4701 CHECK(to_string_result.IsEmpty());
4702 CheckUncle(&try_catch);
4704 Local<Value> to_number_result = obj->ToNumber(isolate);
4705 CHECK(to_number_result.IsEmpty());
4706 CheckUncle(&try_catch);
4708 Local<Value> to_integer_result = obj->ToInteger(isolate);
4709 CHECK(to_integer_result.IsEmpty());
4710 CheckUncle(&try_catch);
4712 Local<Value> to_uint32_result = obj->ToUint32(isolate);
4713 CHECK(to_uint32_result.IsEmpty());
4714 CheckUncle(&try_catch);
4716 Local<Value> to_int32_result = obj->ToInt32(isolate);
4717 CHECK(to_int32_result.IsEmpty());
4718 CheckUncle(&try_catch);
4720 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
4721 CHECK(to_object_result.IsEmpty());
4722 CHECK(try_catch.HasCaught());
4725 int32_t int32_value = obj->Int32Value();
4726 CHECK_EQ(0, int32_value);
4727 CheckUncle(&try_catch);
4729 uint32_t uint32_value = obj->Uint32Value();
4730 CHECK_EQ(0u, uint32_value);
4731 CheckUncle(&try_catch);
4733 double number_value = obj->NumberValue();
4734 CHECK(std::isnan(number_value));
4735 CheckUncle(&try_catch);
4737 int64_t integer_value = obj->IntegerValue();
4738 CHECK_EQ(0, integer_value);
4739 CheckUncle(&try_catch);
4743 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4744 ApiTestFuzzer::Fuzz();
4745 args.GetIsolate()->ThrowException(v8_str("konto"));
4749 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4750 if (args.Length() < 1) {
4751 args.GetReturnValue().Set(false);
4754 v8::HandleScope scope(args.GetIsolate());
4755 v8::TryCatch try_catch(args.GetIsolate());
4756 Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
4757 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4758 args.GetReturnValue().Set(try_catch.HasCaught());
4762 THREADED_TEST(APICatch) {
4763 v8::Isolate* isolate = CcTest::isolate();
4764 v8::HandleScope scope(isolate);
4765 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4766 templ->Set(v8_str("ThrowFromC"),
4767 v8::FunctionTemplate::New(isolate, ThrowFromC));
4768 LocalContext context(0, templ);
4770 "var thrown = false;"
4776 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4777 CHECK(thrown->BooleanValue());
4781 THREADED_TEST(APIThrowTryCatch) {
4782 v8::Isolate* isolate = CcTest::isolate();
4783 v8::HandleScope scope(isolate);
4784 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4785 templ->Set(v8_str("ThrowFromC"),
4786 v8::FunctionTemplate::New(isolate, ThrowFromC));
4787 LocalContext context(0, templ);
4788 v8::TryCatch try_catch(isolate);
4789 CompileRun("ThrowFromC();");
4790 CHECK(try_catch.HasCaught());
4794 // Test that a try-finally block doesn't shadow a try-catch block
4795 // when setting up an external handler.
4797 // BUG(271): Some of the exception propagation does not work on the
4798 // ARM simulator because the simulator separates the C++ stack and the
4799 // JS stack. This test therefore fails on the simulator. The test is
4800 // not threaded to allow the threading tests to run on the simulator.
4801 TEST(TryCatchInTryFinally) {
4802 v8::Isolate* isolate = CcTest::isolate();
4803 v8::HandleScope scope(isolate);
4804 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4805 templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
4806 LocalContext context(0, templ);
4807 Local<Value> result = CompileRun(
4810 " CCatcher('throw 7;');"
4815 CHECK(result->IsTrue());
4819 static void check_reference_error_message(v8::Handle<v8::Message> message,
4820 v8::Handle<v8::Value> data) {
4821 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4822 CHECK(message->Get()->Equals(v8_str(reference_error)));
4826 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4827 ApiTestFuzzer::Fuzz();
4832 // Test that overwritten methods are not invoked on uncaught exception
4833 // formatting. However, they are invoked when performing normal error
4834 // string conversions.
4835 TEST(APIThrowMessageOverwrittenToString) {
4836 v8::Isolate* isolate = CcTest::isolate();
4837 v8::HandleScope scope(isolate);
4838 v8::V8::AddMessageListener(check_reference_error_message);
4839 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4840 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4841 LocalContext context(NULL, templ);
4842 CompileRun("asdf;");
4845 "limit.valueOf = fail;"
4846 "Error.stackTraceLimit = limit;");
4848 CompileRun("Array.prototype.pop = fail;");
4849 CompileRun("Object.prototype.hasOwnProperty = fail;");
4850 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4851 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4852 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4854 "ReferenceError.prototype.toString ="
4855 " function() { return 'Whoops' }");
4856 CompileRun("asdf;");
4857 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4858 CompileRun("asdf;");
4859 CompileRun("ReferenceError.prototype.constructor = void 0;");
4860 CompileRun("asdf;");
4861 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4862 CompileRun("asdf;");
4863 CompileRun("ReferenceError.prototype = new Object();");
4864 CompileRun("asdf;");
4865 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4866 CHECK(string->Equals(v8_str("Whoops")));
4868 "ReferenceError.prototype.constructor = new Object();"
4869 "ReferenceError.prototype.constructor.name = 1;"
4870 "Number.prototype.toString = function() { return 'Whoops'; };"
4871 "ReferenceError.prototype.toString = Object.prototype.toString;");
4872 CompileRun("asdf;");
4873 v8::V8::RemoveMessageListeners(check_reference_error_message);
4877 static void check_custom_error_tostring(v8::Handle<v8::Message> message,
4878 v8::Handle<v8::Value> data) {
4879 const char* uncaught_error = "Uncaught MyError toString";
4880 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4884 TEST(CustomErrorToString) {
4885 LocalContext context;
4886 v8::HandleScope scope(context->GetIsolate());
4887 v8::V8::AddMessageListener(check_custom_error_tostring);
4889 "function MyError(name, message) { "
4890 " this.name = name; "
4891 " this.message = message; "
4893 "MyError.prototype = Object.create(Error.prototype); "
4894 "MyError.prototype.toString = function() { "
4895 " return 'MyError toString'; "
4897 "throw new MyError('my name', 'my message'); ");
4898 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4902 static void check_custom_error_message(v8::Handle<v8::Message> message,
4903 v8::Handle<v8::Value> data) {
4904 const char* uncaught_error = "Uncaught MyError: my message";
4905 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4906 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4910 TEST(CustomErrorMessage) {
4911 LocalContext context;
4912 v8::HandleScope scope(context->GetIsolate());
4913 v8::V8::AddMessageListener(check_custom_error_message);
4917 "function MyError(msg) { "
4918 " this.name = 'MyError'; "
4919 " this.message = msg; "
4921 "MyError.prototype = new Error(); "
4922 "throw new MyError('my message'); ");
4926 "function MyError(msg) { "
4927 " this.name = 'MyError'; "
4928 " this.message = msg; "
4930 "inherits = function(childCtor, parentCtor) { "
4931 " function tempCtor() {}; "
4932 " tempCtor.prototype = parentCtor.prototype; "
4933 " childCtor.superClass_ = parentCtor.prototype; "
4934 " childCtor.prototype = new tempCtor(); "
4935 " childCtor.prototype.constructor = childCtor; "
4937 "inherits(MyError, Error); "
4938 "throw new MyError('my message'); ");
4942 "function MyError(msg) { "
4943 " this.name = 'MyError'; "
4944 " this.message = msg; "
4946 "MyError.prototype = Object.create(Error.prototype); "
4947 "throw new MyError('my message'); ");
4949 v8::V8::RemoveMessageListeners(check_custom_error_message);
4953 static void check_custom_rethrowing_message(v8::Handle<v8::Message> message,
4954 v8::Handle<v8::Value> data) {
4955 const char* uncaught_error = "Uncaught exception";
4956 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4960 TEST(CustomErrorRethrowsOnToString) {
4961 LocalContext context;
4962 v8::HandleScope scope(context->GetIsolate());
4963 v8::V8::AddMessageListener(check_custom_rethrowing_message);
4966 "var e = { toString: function() { throw e; } };"
4967 "try { throw e; } finally {}");
4969 v8::V8::RemoveMessageListeners(check_custom_rethrowing_message);
4973 static void receive_message(v8::Handle<v8::Message> message,
4974 v8::Handle<v8::Value> data) {
4976 message_received = true;
4980 TEST(APIThrowMessage) {
4981 message_received = false;
4982 v8::Isolate* isolate = CcTest::isolate();
4983 v8::HandleScope scope(isolate);
4984 v8::V8::AddMessageListener(receive_message);
4985 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4986 templ->Set(v8_str("ThrowFromC"),
4987 v8::FunctionTemplate::New(isolate, ThrowFromC));
4988 LocalContext context(0, templ);
4989 CompileRun("ThrowFromC();");
4990 CHECK(message_received);
4991 v8::V8::RemoveMessageListeners(receive_message);
4995 TEST(APIThrowMessageAndVerboseTryCatch) {
4996 message_received = false;
4997 v8::Isolate* isolate = CcTest::isolate();
4998 v8::HandleScope scope(isolate);
4999 v8::V8::AddMessageListener(receive_message);
5000 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5001 templ->Set(v8_str("ThrowFromC"),
5002 v8::FunctionTemplate::New(isolate, ThrowFromC));
5003 LocalContext context(0, templ);
5004 v8::TryCatch try_catch(isolate);
5005 try_catch.SetVerbose(true);
5006 Local<Value> result = CompileRun("ThrowFromC();");
5007 CHECK(try_catch.HasCaught());
5008 CHECK(result.IsEmpty());
5009 CHECK(message_received);
5010 v8::V8::RemoveMessageListeners(receive_message);
5014 TEST(APIStackOverflowAndVerboseTryCatch) {
5015 message_received = false;
5016 LocalContext context;
5017 v8::HandleScope scope(context->GetIsolate());
5018 v8::V8::AddMessageListener(receive_message);
5019 v8::TryCatch try_catch(context->GetIsolate());
5020 try_catch.SetVerbose(true);
5021 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5022 CHECK(try_catch.HasCaught());
5023 CHECK(result.IsEmpty());
5024 CHECK(message_received);
5025 v8::V8::RemoveMessageListeners(receive_message);
5029 THREADED_TEST(ExternalScriptException) {
5030 v8::Isolate* isolate = CcTest::isolate();
5031 v8::HandleScope scope(isolate);
5032 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5033 templ->Set(v8_str("ThrowFromC"),
5034 v8::FunctionTemplate::New(isolate, ThrowFromC));
5035 LocalContext context(0, templ);
5037 v8::TryCatch try_catch(isolate);
5038 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5039 CHECK(result.IsEmpty());
5040 CHECK(try_catch.HasCaught());
5041 String::Utf8Value exception_value(try_catch.Exception());
5042 CHECK_EQ(0, strcmp("konto", *exception_value));
5046 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5047 ApiTestFuzzer::Fuzz();
5048 CHECK_EQ(4, args.Length());
5049 int count = args[0]->Int32Value();
5050 int cInterval = args[2]->Int32Value();
5052 args.GetIsolate()->ThrowException(v8_str("FromC"));
5055 Local<v8::Object> global = args.GetIsolate()->GetCurrentContext()->Global();
5056 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5057 v8::Handle<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
5058 if (count % cInterval == 0) {
5059 v8::TryCatch try_catch(args.GetIsolate());
5060 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5061 int expected = args[3]->Int32Value();
5062 if (try_catch.HasCaught()) {
5063 CHECK_EQ(expected, count);
5064 CHECK(result.IsEmpty());
5065 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5067 CHECK_NE(expected, count);
5069 args.GetReturnValue().Set(result);
5072 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5079 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5080 ApiTestFuzzer::Fuzz();
5081 CHECK_EQ(3, args.Length());
5082 bool equality = args[0]->BooleanValue();
5083 int count = args[1]->Int32Value();
5084 int expected = args[2]->Int32Value();
5086 CHECK_EQ(count, expected);
5088 CHECK_NE(count, expected);
5093 THREADED_TEST(EvalInTryFinally) {
5094 LocalContext context;
5095 v8::HandleScope scope(context->GetIsolate());
5096 v8::TryCatch try_catch(context->GetIsolate());
5100 " eval('asldkf (*&^&*^');"
5105 CHECK(!try_catch.HasCaught());
5109 // This test works by making a stack of alternating JavaScript and C
5110 // activations. These activations set up exception handlers with regular
5111 // intervals, one interval for C activations and another for JavaScript
5112 // activations. When enough activations have been created an exception is
5113 // thrown and we check that the right activation catches the exception and that
5114 // no other activations do. The right activation is always the topmost one with
5115 // a handler, regardless of whether it is in JavaScript or C.
5117 // The notation used to describe a test case looks like this:
5119 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5121 // Each entry is an activation, either JS or C. The index is the count at that
5122 // level. Stars identify activations with exception handlers, the @ identifies
5123 // the exception handler that should catch the exception.
5125 // BUG(271): Some of the exception propagation does not work on the
5126 // ARM simulator because the simulator separates the C++ stack and the
5127 // JS stack. This test therefore fails on the simulator. The test is
5128 // not threaded to allow the threading tests to run on the simulator.
5129 TEST(ExceptionOrder) {
5130 v8::Isolate* isolate = CcTest::isolate();
5131 v8::HandleScope scope(isolate);
5132 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5133 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5134 templ->Set(v8_str("CThrowCountDown"),
5135 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5136 LocalContext context(0, templ);
5138 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5139 " if (count == 0) throw 'FromJS';"
5140 " if (count % jsInterval == 0) {"
5142 " var value = CThrowCountDown(count - 1,"
5146 " check(false, count, expected);"
5149 " check(true, count, expected);"
5152 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5155 Local<Function> fun =
5156 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5159 // count jsInterval cInterval expected
5161 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5162 v8::Handle<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
5163 fun->Call(fun, argc, a0);
5165 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5166 v8::Handle<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
5167 fun->Call(fun, argc, a1);
5169 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5170 v8::Handle<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
5171 fun->Call(fun, argc, a2);
5173 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5174 v8::Handle<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
5175 fun->Call(fun, argc, a3);
5177 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5178 v8::Handle<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
5179 fun->Call(fun, argc, a4);
5181 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5182 v8::Handle<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
5183 fun->Call(fun, argc, a5);
5187 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5188 ApiTestFuzzer::Fuzz();
5189 CHECK_EQ(1, args.Length());
5190 args.GetIsolate()->ThrowException(args[0]);
5194 THREADED_TEST(ThrowValues) {
5195 v8::Isolate* isolate = CcTest::isolate();
5196 v8::HandleScope scope(isolate);
5197 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5198 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5199 LocalContext context(0, templ);
5200 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5201 "function Run(obj) {"
5207 " return 'no exception';"
5209 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5210 CHECK_EQ(5u, result->Length());
5211 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5212 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5213 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5214 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5215 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5216 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5217 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5221 THREADED_TEST(CatchZero) {
5222 LocalContext context;
5223 v8::HandleScope scope(context->GetIsolate());
5224 v8::TryCatch try_catch(context->GetIsolate());
5225 CHECK(!try_catch.HasCaught());
5226 CompileRun("throw 10");
5227 CHECK(try_catch.HasCaught());
5228 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5230 CHECK(!try_catch.HasCaught());
5231 CompileRun("throw 0");
5232 CHECK(try_catch.HasCaught());
5233 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5237 THREADED_TEST(CatchExceptionFromWith) {
5238 LocalContext context;
5239 v8::HandleScope scope(context->GetIsolate());
5240 v8::TryCatch try_catch(context->GetIsolate());
5241 CHECK(!try_catch.HasCaught());
5242 CompileRun("var o = {}; with (o) { throw 42; }");
5243 CHECK(try_catch.HasCaught());
5247 THREADED_TEST(TryCatchAndFinallyHidingException) {
5248 LocalContext context;
5249 v8::HandleScope scope(context->GetIsolate());
5250 v8::TryCatch try_catch(context->GetIsolate());
5251 CHECK(!try_catch.HasCaught());
5252 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5253 CompileRun("f({toString: function() { throw 42; }});");
5254 CHECK(!try_catch.HasCaught());
5258 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5259 v8::TryCatch try_catch(args.GetIsolate());
5263 THREADED_TEST(TryCatchAndFinally) {
5264 LocalContext context;
5265 v8::Isolate* isolate = context->GetIsolate();
5266 v8::HandleScope scope(isolate);
5267 context->Global()->Set(
5268 v8_str("native_with_try_catch"),
5269 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5270 v8::TryCatch try_catch(isolate);
5271 CHECK(!try_catch.HasCaught());
5274 " throw new Error('a');\n"
5276 " native_with_try_catch();\n"
5278 CHECK(try_catch.HasCaught());
5282 static void TryCatchNested1Helper(int depth) {
5284 v8::TryCatch try_catch(CcTest::isolate());
5285 try_catch.SetVerbose(true);
5286 TryCatchNested1Helper(depth - 1);
5287 CHECK(try_catch.HasCaught());
5288 try_catch.ReThrow();
5290 CcTest::isolate()->ThrowException(v8_str("E1"));
5295 static void TryCatchNested2Helper(int depth) {
5297 v8::TryCatch try_catch(CcTest::isolate());
5298 try_catch.SetVerbose(true);
5299 TryCatchNested2Helper(depth - 1);
5300 CHECK(try_catch.HasCaught());
5301 try_catch.ReThrow();
5303 CompileRun("throw 'E2';");
5308 TEST(TryCatchNested) {
5309 v8::V8::Initialize();
5310 LocalContext context;
5311 v8::HandleScope scope(context->GetIsolate());
5314 // Test nested try-catch with a native throw in the end.
5315 v8::TryCatch try_catch(context->GetIsolate());
5316 TryCatchNested1Helper(5);
5317 CHECK(try_catch.HasCaught());
5318 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5322 // Test nested try-catch with a JavaScript throw in the end.
5323 v8::TryCatch try_catch(context->GetIsolate());
5324 TryCatchNested2Helper(5);
5325 CHECK(try_catch.HasCaught());
5326 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5331 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5332 CHECK(try_catch->HasCaught());
5333 Handle<Message> message = try_catch->Message();
5334 Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5335 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5337 strcmp(*v8::String::Utf8Value(message->Get()), "Uncaught Error: a"));
5338 CHECK_EQ(1, message->GetLineNumber());
5339 CHECK_EQ(0, message->GetStartColumn());
5343 void TryCatchMixedNestingHelper(
5344 const v8::FunctionCallbackInfo<v8::Value>& args) {
5345 ApiTestFuzzer::Fuzz();
5346 v8::TryCatch try_catch(args.GetIsolate());
5347 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5348 CHECK(try_catch.HasCaught());
5349 TryCatchMixedNestingCheck(&try_catch);
5350 try_catch.ReThrow();
5354 // This test ensures that an outer TryCatch in the following situation:
5355 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5356 // does not clobber the Message object generated for the inner TryCatch.
5357 // This exercises the ability of TryCatch.ReThrow() to restore the
5358 // inner pending Message before throwing the exception again.
5359 TEST(TryCatchMixedNesting) {
5360 v8::Isolate* isolate = CcTest::isolate();
5361 v8::HandleScope scope(isolate);
5362 v8::V8::Initialize();
5363 v8::TryCatch try_catch(isolate);
5364 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5365 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5366 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5367 LocalContext context(0, templ);
5368 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5369 TryCatchMixedNestingCheck(&try_catch);
5373 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5374 ApiTestFuzzer::Fuzz();
5375 v8::TryCatch try_catch(args.GetIsolate());
5376 args.GetIsolate()->ThrowException(v8_str("boom"));
5377 CHECK(try_catch.HasCaught());
5381 TEST(TryCatchNative) {
5382 v8::Isolate* isolate = CcTest::isolate();
5383 v8::HandleScope scope(isolate);
5384 v8::V8::Initialize();
5385 v8::TryCatch try_catch(isolate);
5386 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5387 templ->Set(v8_str("TryCatchNativeHelper"),
5388 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5389 LocalContext context(0, templ);
5390 CompileRun("TryCatchNativeHelper();");
5391 CHECK(!try_catch.HasCaught());
5395 void TryCatchNativeResetHelper(
5396 const v8::FunctionCallbackInfo<v8::Value>& args) {
5397 ApiTestFuzzer::Fuzz();
5398 v8::TryCatch try_catch(args.GetIsolate());
5399 args.GetIsolate()->ThrowException(v8_str("boom"));
5400 CHECK(try_catch.HasCaught());
5402 CHECK(!try_catch.HasCaught());
5406 TEST(TryCatchNativeReset) {
5407 v8::Isolate* isolate = CcTest::isolate();
5408 v8::HandleScope scope(isolate);
5409 v8::V8::Initialize();
5410 v8::TryCatch try_catch(isolate);
5411 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5412 templ->Set(v8_str("TryCatchNativeResetHelper"),
5413 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5414 LocalContext context(0, templ);
5415 CompileRun("TryCatchNativeResetHelper();");
5416 CHECK(!try_catch.HasCaught());
5420 THREADED_TEST(Equality) {
5421 LocalContext context;
5422 v8::Isolate* isolate = context->GetIsolate();
5423 v8::HandleScope scope(context->GetIsolate());
5424 // Check that equality works at all before relying on CHECK_EQ
5425 CHECK(v8_str("a")->Equals(v8_str("a")));
5426 CHECK(!v8_str("a")->Equals(v8_str("b")));
5428 CHECK(v8_str("a")->Equals(v8_str("a")));
5429 CHECK(!v8_str("a")->Equals(v8_str("b")));
5430 CHECK(v8_num(1)->Equals(v8_num(1)));
5431 CHECK(v8_num(1.00)->Equals(v8_num(1)));
5432 CHECK(!v8_num(1)->Equals(v8_num(2)));
5434 // Assume String is not internalized.
5435 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5436 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5437 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5438 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5439 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5440 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5441 Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
5442 CHECK(!not_a_number->StrictEquals(not_a_number));
5443 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5444 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5446 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5447 v8::Persistent<v8::Object> alias(isolate, obj);
5448 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5451 CHECK(v8_str("a")->SameValue(v8_str("a")));
5452 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5453 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5454 CHECK(v8_num(1)->SameValue(v8_num(1)));
5455 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5456 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5457 CHECK(not_a_number->SameValue(not_a_number));
5458 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5459 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5463 THREADED_TEST(MultiRun) {
5464 LocalContext context;
5465 v8::HandleScope scope(context->GetIsolate());
5466 Local<Script> script = v8_compile("x");
5467 for (int i = 0; i < 10; i++) script->Run();
5471 static void GetXValue(Local<String> name,
5472 const v8::PropertyCallbackInfo<v8::Value>& info) {
5473 ApiTestFuzzer::Fuzz();
5474 CHECK(info.Data()->Equals(v8_str("donut")));
5475 CHECK(name->Equals(v8_str("x")));
5476 info.GetReturnValue().Set(name);
5480 THREADED_TEST(SimplePropertyRead) {
5481 LocalContext context;
5482 v8::Isolate* isolate = context->GetIsolate();
5483 v8::HandleScope scope(isolate);
5484 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5485 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5486 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5487 Local<Script> script = v8_compile("obj.x");
5488 for (int i = 0; i < 10; i++) {
5489 Local<Value> result = script->Run();
5490 CHECK(result->Equals(v8_str("x")));
5495 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5496 LocalContext context;
5497 v8::Isolate* isolate = context->GetIsolate();
5498 v8::HandleScope scope(isolate);
5499 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5500 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5501 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5503 // Uses getOwnPropertyDescriptor to check the configurable status
5504 Local<Script> script_desc = v8_compile(
5505 "var prop = Object.getOwnPropertyDescriptor( "
5507 "prop.configurable;");
5508 Local<Value> result = script_desc->Run();
5509 CHECK_EQ(result->BooleanValue(), true);
5511 // Redefine get - but still configurable
5512 Local<Script> script_define = v8_compile(
5513 "var desc = { get: function(){return 42; },"
5514 " configurable: true };"
5515 "Object.defineProperty(obj, 'x', desc);"
5517 result = script_define->Run();
5518 CHECK(result->Equals(v8_num(42)));
5520 // Check that the accessor is still configurable
5521 result = script_desc->Run();
5522 CHECK_EQ(result->BooleanValue(), true);
5524 // Redefine to a non-configurable
5525 script_define = v8_compile(
5526 "var desc = { get: function(){return 43; },"
5527 " configurable: false };"
5528 "Object.defineProperty(obj, 'x', desc);"
5530 result = script_define->Run();
5531 CHECK(result->Equals(v8_num(43)));
5532 result = script_desc->Run();
5533 CHECK_EQ(result->BooleanValue(), false);
5535 // Make sure that it is not possible to redefine again
5536 v8::TryCatch try_catch(isolate);
5537 result = script_define->Run();
5538 CHECK(try_catch.HasCaught());
5539 String::Utf8Value exception_value(try_catch.Exception());
5541 strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5545 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5546 v8::Isolate* isolate = CcTest::isolate();
5547 v8::HandleScope scope(isolate);
5548 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5549 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5550 LocalContext context;
5551 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5553 Local<Script> script_desc = v8_compile(
5555 "Object.getOwnPropertyDescriptor( "
5557 "prop.configurable;");
5558 Local<Value> result = script_desc->Run();
5559 CHECK_EQ(result->BooleanValue(), true);
5561 Local<Script> script_define = v8_compile(
5562 "var desc = {get: function(){return 42; },"
5563 " configurable: true };"
5564 "Object.defineProperty(obj, 'x', desc);"
5566 result = script_define->Run();
5567 CHECK(result->Equals(v8_num(42)));
5570 result = script_desc->Run();
5571 CHECK_EQ(result->BooleanValue(), true);
5574 script_define = v8_compile(
5575 "var desc = {get: function(){return 43; },"
5576 " configurable: false };"
5577 "Object.defineProperty(obj, 'x', desc);"
5579 result = script_define->Run();
5580 CHECK(result->Equals(v8_num(43)));
5581 result = script_desc->Run();
5583 CHECK_EQ(result->BooleanValue(), false);
5585 v8::TryCatch try_catch(isolate);
5586 result = script_define->Run();
5587 CHECK(try_catch.HasCaught());
5588 String::Utf8Value exception_value(try_catch.Exception());
5590 strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5594 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5596 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5600 THREADED_TEST(DefineAPIAccessorOnObject) {
5601 v8::Isolate* isolate = CcTest::isolate();
5602 v8::HandleScope scope(isolate);
5603 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5604 LocalContext context;
5606 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5607 CompileRun("var obj2 = {};");
5609 CHECK(CompileRun("obj1.x")->IsUndefined());
5610 CHECK(CompileRun("obj2.x")->IsUndefined());
5612 CHECK(GetGlobalProperty(&context, "obj1")
5613 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5615 ExpectString("obj1.x", "x");
5616 CHECK(CompileRun("obj2.x")->IsUndefined());
5618 CHECK(GetGlobalProperty(&context, "obj2")
5619 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5621 ExpectString("obj1.x", "x");
5622 ExpectString("obj2.x", "x");
5624 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5625 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5628 "Object.defineProperty(obj1, 'x',"
5629 "{ get: function() { return 'y'; }, configurable: true })");
5631 ExpectString("obj1.x", "y");
5632 ExpectString("obj2.x", "x");
5635 "Object.defineProperty(obj2, 'x',"
5636 "{ get: function() { return 'y'; }, configurable: true })");
5638 ExpectString("obj1.x", "y");
5639 ExpectString("obj2.x", "y");
5641 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5642 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5644 CHECK(GetGlobalProperty(&context, "obj1")
5645 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5646 CHECK(GetGlobalProperty(&context, "obj2")
5647 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5649 ExpectString("obj1.x", "x");
5650 ExpectString("obj2.x", "x");
5652 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5653 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5655 // Define getters/setters, but now make them not configurable.
5657 "Object.defineProperty(obj1, 'x',"
5658 "{ get: function() { return 'z'; }, configurable: false })");
5660 "Object.defineProperty(obj2, 'x',"
5661 "{ get: function() { return 'z'; }, configurable: false })");
5663 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5664 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5666 ExpectString("obj1.x", "z");
5667 ExpectString("obj2.x", "z");
5669 CHECK(!GetGlobalProperty(&context, "obj1")
5670 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5671 CHECK(!GetGlobalProperty(&context, "obj2")
5672 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5674 ExpectString("obj1.x", "z");
5675 ExpectString("obj2.x", "z");
5679 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5680 v8::Isolate* isolate = CcTest::isolate();
5681 v8::HandleScope scope(isolate);
5682 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5683 LocalContext context;
5685 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5686 CompileRun("var obj2 = {};");
5688 CHECK(GetGlobalProperty(&context, "obj1")
5689 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"),
5690 v8::DEFAULT, v8::DontDelete));
5691 CHECK(GetGlobalProperty(&context, "obj2")
5692 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"),
5693 v8::DEFAULT, v8::DontDelete));
5695 ExpectString("obj1.x", "x");
5696 ExpectString("obj2.x", "x");
5698 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5699 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5701 CHECK(!GetGlobalProperty(&context, "obj1")
5702 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5703 CHECK(!GetGlobalProperty(&context, "obj2")
5704 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5707 v8::TryCatch try_catch(isolate);
5709 "Object.defineProperty(obj1, 'x',"
5710 "{get: function() { return 'func'; }})");
5711 CHECK(try_catch.HasCaught());
5712 String::Utf8Value exception_value(try_catch.Exception());
5714 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5717 v8::TryCatch try_catch(isolate);
5719 "Object.defineProperty(obj2, 'x',"
5720 "{get: function() { return 'func'; }})");
5721 CHECK(try_catch.HasCaught());
5722 String::Utf8Value exception_value(try_catch.Exception());
5724 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5729 static void Get239Value(Local<String> name,
5730 const v8::PropertyCallbackInfo<v8::Value>& info) {
5731 ApiTestFuzzer::Fuzz();
5732 CHECK(info.Data()->Equals(v8_str("donut")));
5733 CHECK(name->Equals(v8_str("239")));
5734 info.GetReturnValue().Set(name);
5738 THREADED_TEST(ElementAPIAccessor) {
5739 v8::Isolate* isolate = CcTest::isolate();
5740 v8::HandleScope scope(isolate);
5741 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5742 LocalContext context;
5744 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5745 CompileRun("var obj2 = {};");
5747 CHECK(GetGlobalProperty(&context, "obj1")
5748 ->SetAccessor(v8_str("239"), Get239Value, NULL, v8_str("donut")));
5749 CHECK(GetGlobalProperty(&context, "obj2")
5750 ->SetAccessor(v8_str("239"), Get239Value, NULL, v8_str("donut")));
5752 ExpectString("obj1[239]", "239");
5753 ExpectString("obj2[239]", "239");
5754 ExpectString("obj1['239']", "239");
5755 ExpectString("obj2['239']", "239");
5759 v8::Persistent<Value> xValue;
5762 static void SetXValue(Local<String> name, Local<Value> value,
5763 const v8::PropertyCallbackInfo<void>& info) {
5764 CHECK(value->Equals(v8_num(4)));
5765 CHECK(info.Data()->Equals(v8_str("donut")));
5766 CHECK(name->Equals(v8_str("x")));
5767 CHECK(xValue.IsEmpty());
5768 xValue.Reset(info.GetIsolate(), value);
5772 THREADED_TEST(SimplePropertyWrite) {
5773 v8::Isolate* isolate = CcTest::isolate();
5774 v8::HandleScope scope(isolate);
5775 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5776 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5777 LocalContext context;
5778 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5779 Local<Script> script = v8_compile("obj.x = 4");
5780 for (int i = 0; i < 10; i++) {
5781 CHECK(xValue.IsEmpty());
5783 CHECK(v8_num(4)->Equals(Local<Value>::New(CcTest::isolate(), xValue)));
5789 THREADED_TEST(SetterOnly) {
5790 v8::Isolate* isolate = CcTest::isolate();
5791 v8::HandleScope scope(isolate);
5792 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5793 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5794 LocalContext context;
5795 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5796 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5797 for (int i = 0; i < 10; i++) {
5798 CHECK(xValue.IsEmpty());
5800 CHECK(v8_num(4)->Equals(Local<Value>::New(CcTest::isolate(), xValue)));
5806 THREADED_TEST(NoAccessors) {
5807 v8::Isolate* isolate = CcTest::isolate();
5808 v8::HandleScope scope(isolate);
5809 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5810 templ->SetAccessor(v8_str("x"), static_cast<v8::AccessorGetterCallback>(NULL),
5811 NULL, v8_str("donut"));
5812 LocalContext context;
5813 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5814 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5815 for (int i = 0; i < 10; i++) {
5821 THREADED_TEST(MultiContexts) {
5822 v8::Isolate* isolate = CcTest::isolate();
5823 v8::HandleScope scope(isolate);
5824 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5825 templ->Set(v8_str("dummy"),
5826 v8::FunctionTemplate::New(isolate, DummyCallHandler));
5828 Local<String> password = v8_str("Password");
5830 // Create an environment
5831 LocalContext context0(0, templ);
5832 context0->SetSecurityToken(password);
5833 v8::Handle<v8::Object> global0 = context0->Global();
5834 global0->Set(v8_str("custom"), v8_num(1234));
5835 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5837 // Create an independent environment
5838 LocalContext context1(0, templ);
5839 context1->SetSecurityToken(password);
5840 v8::Handle<v8::Object> global1 = context1->Global();
5841 global1->Set(v8_str("custom"), v8_num(1234));
5842 CHECK(!global0->Equals(global1));
5843 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5844 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
5846 // Now create a new context with the old global
5847 LocalContext context2(0, templ, global1);
5848 context2->SetSecurityToken(password);
5849 v8::Handle<v8::Object> global2 = context2->Global();
5850 CHECK(global1->Equals(global2));
5851 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
5852 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
5856 THREADED_TEST(FunctionPrototypeAcrossContexts) {
5857 // Make sure that functions created by cloning boilerplates cannot
5858 // communicate through their __proto__ field.
5860 v8::HandleScope scope(CcTest::isolate());
5863 v8::Handle<v8::Object> global0 = env0->Global();
5864 v8::Handle<v8::Object> object0 =
5865 global0->Get(v8_str("Object")).As<v8::Object>();
5866 v8::Handle<v8::Object> tostring0 =
5867 object0->Get(v8_str("toString")).As<v8::Object>();
5868 v8::Handle<v8::Object> proto0 =
5869 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
5870 proto0->Set(v8_str("custom"), v8_num(1234));
5873 v8::Handle<v8::Object> global1 = env1->Global();
5874 v8::Handle<v8::Object> object1 =
5875 global1->Get(v8_str("Object")).As<v8::Object>();
5876 v8::Handle<v8::Object> tostring1 =
5877 object1->Get(v8_str("toString")).As<v8::Object>();
5878 v8::Handle<v8::Object> proto1 =
5879 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
5880 CHECK(!proto1->Has(v8_str("custom")));
5884 THREADED_TEST(Regress892105) {
5885 // Make sure that object and array literals created by cloning
5886 // boilerplates cannot communicate through their __proto__
5887 // field. This is rather difficult to check, but we try to add stuff
5888 // to Object.prototype and Array.prototype and create a new
5889 // environment. This should succeed.
5891 v8::HandleScope scope(CcTest::isolate());
5893 Local<String> source = v8_str(
5894 "Object.prototype.obj = 1234;"
5895 "Array.prototype.arr = 4567;"
5899 Local<Script> script0 = v8_compile(source);
5900 CHECK_EQ(8901.0, script0->Run()->NumberValue());
5903 Local<Script> script1 = v8_compile(source);
5904 CHECK_EQ(8901.0, script1->Run()->NumberValue());
5908 THREADED_TEST(UndetectableObject) {
5910 v8::HandleScope scope(env->GetIsolate());
5912 Local<v8::FunctionTemplate> desc =
5913 v8::FunctionTemplate::New(env->GetIsolate());
5914 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5916 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5917 env->Global()->Set(v8_str("undetectable"), obj);
5919 ExpectString("undetectable.toString()", "[object Object]");
5920 ExpectString("typeof undetectable", "undefined");
5921 ExpectString("typeof(undetectable)", "undefined");
5922 ExpectBoolean("typeof undetectable == 'undefined'", true);
5923 ExpectBoolean("typeof undetectable == 'object'", false);
5924 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
5925 ExpectBoolean("!undetectable", true);
5927 ExpectObject("true&&undetectable", obj);
5928 ExpectBoolean("false&&undetectable", false);
5929 ExpectBoolean("true||undetectable", true);
5930 ExpectObject("false||undetectable", obj);
5932 ExpectObject("undetectable&&true", obj);
5933 ExpectObject("undetectable&&false", obj);
5934 ExpectBoolean("undetectable||true", true);
5935 ExpectBoolean("undetectable||false", false);
5937 ExpectBoolean("undetectable==null", true);
5938 ExpectBoolean("null==undetectable", true);
5939 ExpectBoolean("undetectable==undefined", true);
5940 ExpectBoolean("undefined==undetectable", true);
5941 ExpectBoolean("undetectable==undetectable", true);
5944 ExpectBoolean("undetectable===null", false);
5945 ExpectBoolean("null===undetectable", false);
5946 ExpectBoolean("undetectable===undefined", false);
5947 ExpectBoolean("undefined===undetectable", false);
5948 ExpectBoolean("undetectable===undetectable", true);
5952 THREADED_TEST(VoidLiteral) {
5954 v8::Isolate* isolate = env->GetIsolate();
5955 v8::HandleScope scope(isolate);
5957 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
5958 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5960 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5961 env->Global()->Set(v8_str("undetectable"), obj);
5963 ExpectBoolean("undefined == void 0", true);
5964 ExpectBoolean("undetectable == void 0", true);
5965 ExpectBoolean("null == void 0", true);
5966 ExpectBoolean("undefined === void 0", true);
5967 ExpectBoolean("undetectable === void 0", false);
5968 ExpectBoolean("null === void 0", false);
5970 ExpectBoolean("void 0 == undefined", true);
5971 ExpectBoolean("void 0 == undetectable", true);
5972 ExpectBoolean("void 0 == null", true);
5973 ExpectBoolean("void 0 === undefined", true);
5974 ExpectBoolean("void 0 === undetectable", false);
5975 ExpectBoolean("void 0 === null", false);
5980 " return x === void 0;"
5982 " return e.toString();"
5985 "ReferenceError: x is not defined");
5989 " return void 0 === x;"
5991 " return e.toString();"
5994 "ReferenceError: x is not defined");
5998 THREADED_TEST(ExtensibleOnUndetectable) {
6000 v8::Isolate* isolate = env->GetIsolate();
6001 v8::HandleScope scope(isolate);
6003 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6004 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6006 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6007 env->Global()->Set(v8_str("undetectable"), obj);
6009 Local<String> source = v8_str(
6010 "undetectable.x = 42;"
6013 Local<Script> script = v8_compile(source);
6015 CHECK(v8::Integer::New(isolate, 42)->Equals(script->Run()));
6017 ExpectBoolean("Object.isExtensible(undetectable)", true);
6019 source = v8_str("Object.preventExtensions(undetectable);");
6020 script = v8_compile(source);
6022 ExpectBoolean("Object.isExtensible(undetectable)", false);
6024 source = v8_str("undetectable.y = 2000;");
6025 script = v8_compile(source);
6027 ExpectBoolean("undetectable.y == undefined", true);
6031 // The point of this test is type checking. We run it only so compilers
6032 // don't complain about an unused function.
6033 TEST(PersistentHandles) {
6035 v8::Isolate* isolate = CcTest::isolate();
6036 v8::HandleScope scope(isolate);
6037 Local<String> str = v8_str("foo");
6038 v8::Persistent<String> p_str(isolate, str);
6040 Local<Script> scr = v8_compile("");
6041 v8::Persistent<Script> p_scr(isolate, scr);
6043 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6044 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6049 static void HandleLogDelegator(
6050 const v8::FunctionCallbackInfo<v8::Value>& args) {
6051 ApiTestFuzzer::Fuzz();
6055 THREADED_TEST(GlobalObjectTemplate) {
6056 v8::Isolate* isolate = CcTest::isolate();
6057 v8::HandleScope handle_scope(isolate);
6058 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6059 global_template->Set(v8_str("JSNI_Log"),
6060 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6061 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6062 Context::Scope context_scope(context);
6063 CompileRun("JSNI_Log('LOG')");
6067 static const char* kSimpleExtensionSource =
6073 TEST(SimpleExtensions) {
6074 v8::HandleScope handle_scope(CcTest::isolate());
6075 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6076 const char* extension_names[] = {"simpletest"};
6077 v8::ExtensionConfiguration extensions(1, extension_names);
6078 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6079 Context::Scope lock(context);
6080 v8::Handle<Value> result = CompileRun("Foo()");
6081 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6085 static const char* kStackTraceFromExtensionSource =
6087 " throw new Error();"
6094 TEST(StackTraceInExtension) {
6095 v8::HandleScope handle_scope(CcTest::isolate());
6096 v8::RegisterExtension(
6097 new Extension("stacktracetest", kStackTraceFromExtensionSource));
6098 const char* extension_names[] = {"stacktracetest"};
6099 v8::ExtensionConfiguration extensions(1, extension_names);
6100 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6101 Context::Scope lock(context);
6103 "function user() { bar(); }"
6105 "try{ user(); } catch (e) { error = e; }");
6106 CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
6107 CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
6108 CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
6112 TEST(NullExtensions) {
6113 v8::HandleScope handle_scope(CcTest::isolate());
6114 v8::RegisterExtension(new Extension("nulltest", NULL));
6115 const char* extension_names[] = {"nulltest"};
6116 v8::ExtensionConfiguration extensions(1, extension_names);
6117 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6118 Context::Scope lock(context);
6119 v8::Handle<Value> result = CompileRun("1+3");
6120 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6124 static const char* kEmbeddedExtensionSource =
6125 "function Ret54321(){return 54321;}~~@@$"
6126 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6127 static const int kEmbeddedExtensionSourceValidLen = 34;
6130 TEST(ExtensionMissingSourceLength) {
6131 v8::HandleScope handle_scope(CcTest::isolate());
6132 v8::RegisterExtension(
6133 new Extension("srclentest_fail", kEmbeddedExtensionSource));
6134 const char* extension_names[] = {"srclentest_fail"};
6135 v8::ExtensionConfiguration extensions(1, extension_names);
6136 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6137 CHECK(0 == *context);
6141 TEST(ExtensionWithSourceLength) {
6142 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6143 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6144 v8::HandleScope handle_scope(CcTest::isolate());
6145 i::ScopedVector<char> extension_name(32);
6146 i::SNPrintF(extension_name, "ext #%d", source_len);
6147 v8::RegisterExtension(new Extension(
6148 extension_name.start(), kEmbeddedExtensionSource, 0, 0, source_len));
6149 const char* extension_names[1] = {extension_name.start()};
6150 v8::ExtensionConfiguration extensions(1, extension_names);
6151 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6152 if (source_len == kEmbeddedExtensionSourceValidLen) {
6153 Context::Scope lock(context);
6154 v8::Handle<Value> result = CompileRun("Ret54321()");
6155 CHECK(v8::Integer::New(CcTest::isolate(), 54321)->Equals(result));
6157 // Anything but exactly the right length should fail to compile.
6158 CHECK(0 == *context);
6164 static const char* kEvalExtensionSource1 =
6165 "function UseEval1() {"
6167 " return eval('x');"
6171 static const char* kEvalExtensionSource2 =
6175 " return eval('x');"
6177 " this.UseEval2 = e;"
6181 TEST(UseEvalFromExtension) {
6182 v8::HandleScope handle_scope(CcTest::isolate());
6183 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6184 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6185 const char* extension_names[] = {"evaltest1", "evaltest2"};
6186 v8::ExtensionConfiguration extensions(2, extension_names);
6187 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6188 Context::Scope lock(context);
6189 v8::Handle<Value> result = CompileRun("UseEval1()");
6190 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6191 result = CompileRun("UseEval2()");
6192 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6196 static const char* kWithExtensionSource1 =
6197 "function UseWith1() {"
6199 " with({x:87}) { return x; }"
6203 static const char* kWithExtensionSource2 =
6207 " with ({x:87}) { return x; }"
6209 " this.UseWith2 = e;"
6213 TEST(UseWithFromExtension) {
6214 v8::HandleScope handle_scope(CcTest::isolate());
6215 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6216 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6217 const char* extension_names[] = {"withtest1", "withtest2"};
6218 v8::ExtensionConfiguration extensions(2, extension_names);
6219 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6220 Context::Scope lock(context);
6221 v8::Handle<Value> result = CompileRun("UseWith1()");
6222 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 87)));
6223 result = CompileRun("UseWith2()");
6224 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 87)));
6228 TEST(AutoExtensions) {
6229 v8::HandleScope handle_scope(CcTest::isolate());
6230 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6231 extension->set_auto_enable(true);
6232 v8::RegisterExtension(extension);
6233 v8::Handle<Context> context = Context::New(CcTest::isolate());
6234 Context::Scope lock(context);
6235 v8::Handle<Value> result = CompileRun("Foo()");
6236 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6240 static const char* kSyntaxErrorInExtensionSource = "[";
6243 // Test that a syntax error in an extension does not cause a fatal
6244 // error but results in an empty context.
6245 TEST(SyntaxErrorExtensions) {
6246 v8::HandleScope handle_scope(CcTest::isolate());
6247 v8::RegisterExtension(
6248 new Extension("syntaxerror", kSyntaxErrorInExtensionSource));
6249 const char* extension_names[] = {"syntaxerror"};
6250 v8::ExtensionConfiguration extensions(1, extension_names);
6251 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6252 CHECK(context.IsEmpty());
6256 static const char* kExceptionInExtensionSource = "throw 42";
6259 // Test that an exception when installing an extension does not cause
6260 // a fatal error but results in an empty context.
6261 TEST(ExceptionExtensions) {
6262 v8::HandleScope handle_scope(CcTest::isolate());
6263 v8::RegisterExtension(
6264 new Extension("exception", kExceptionInExtensionSource));
6265 const char* extension_names[] = {"exception"};
6266 v8::ExtensionConfiguration extensions(1, extension_names);
6267 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6268 CHECK(context.IsEmpty());
6272 static const char* kNativeCallInExtensionSource =
6273 "function call_runtime_last_index_of(x) {"
6274 " return %StringLastIndexOf(x, 'bob', 10);"
6278 static const char* kNativeCallTest =
6279 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6281 // Test that a native runtime calls are supported in extensions.
6282 TEST(NativeCallInExtensions) {
6283 v8::HandleScope handle_scope(CcTest::isolate());
6284 v8::RegisterExtension(
6285 new Extension("nativecall", kNativeCallInExtensionSource));
6286 const char* extension_names[] = {"nativecall"};
6287 v8::ExtensionConfiguration extensions(1, extension_names);
6288 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6289 Context::Scope lock(context);
6290 v8::Handle<Value> result = CompileRun(kNativeCallTest);
6291 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 3)));
6295 class NativeFunctionExtension : public Extension {
6297 NativeFunctionExtension(const char* name, const char* source,
6298 v8::FunctionCallback fun = &Echo)
6299 : Extension(name, source), function_(fun) {}
6301 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6302 v8::Isolate* isolate, v8::Handle<v8::String> name) {
6303 return v8::FunctionTemplate::New(isolate, function_);
6306 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6307 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6311 v8::FunctionCallback function_;
6315 TEST(NativeFunctionDeclaration) {
6316 v8::HandleScope handle_scope(CcTest::isolate());
6317 const char* name = "nativedecl";
6318 v8::RegisterExtension(
6319 new NativeFunctionExtension(name, "native function foo();"));
6320 const char* extension_names[] = {name};
6321 v8::ExtensionConfiguration extensions(1, extension_names);
6322 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6323 Context::Scope lock(context);
6324 v8::Handle<Value> result = CompileRun("foo(42);");
6325 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6329 TEST(NativeFunctionDeclarationError) {
6330 v8::HandleScope handle_scope(CcTest::isolate());
6331 const char* name = "nativedeclerr";
6332 // Syntax error in extension code.
6333 v8::RegisterExtension(
6334 new NativeFunctionExtension(name, "native\nfunction foo();"));
6335 const char* extension_names[] = {name};
6336 v8::ExtensionConfiguration extensions(1, extension_names);
6337 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6338 CHECK(context.IsEmpty());
6342 TEST(NativeFunctionDeclarationErrorEscape) {
6343 v8::HandleScope handle_scope(CcTest::isolate());
6344 const char* name = "nativedeclerresc";
6345 // Syntax error in extension code - escape code in "native" means that
6346 // it's not treated as a keyword.
6347 v8::RegisterExtension(
6348 new NativeFunctionExtension(name, "nativ\\u0065 function foo();"));
6349 const char* extension_names[] = {name};
6350 v8::ExtensionConfiguration extensions(1, extension_names);
6351 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6352 CHECK(context.IsEmpty());
6356 static void CheckDependencies(const char* name, const char* expected) {
6357 v8::HandleScope handle_scope(CcTest::isolate());
6358 v8::ExtensionConfiguration config(1, &name);
6359 LocalContext context(&config);
6360 CHECK(String::NewFromUtf8(CcTest::isolate(), expected)
6361 ->Equals(context->Global()->Get(v8_str("loaded"))));
6372 THREADED_TEST(ExtensionDependency) {
6373 static const char* kEDeps[] = {"D"};
6374 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6375 static const char* kDDeps[] = {"B", "C"};
6376 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6377 static const char* kBCDeps[] = {"A"};
6378 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6379 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6380 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6381 CheckDependencies("A", "undefinedA");
6382 CheckDependencies("B", "undefinedAB");
6383 CheckDependencies("C", "undefinedAC");
6384 CheckDependencies("D", "undefinedABCD");
6385 CheckDependencies("E", "undefinedABCDE");
6386 v8::HandleScope handle_scope(CcTest::isolate());
6387 static const char* exts[2] = {"C", "E"};
6388 v8::ExtensionConfiguration config(2, exts);
6389 LocalContext context(&config);
6390 CHECK(v8_str("undefinedACBDE")
6391 ->Equals(context->Global()->Get(v8_str("loaded"))));
6395 static const char* kExtensionTestScript =
6396 "native function A();"
6397 "native function B();"
6398 "native function C();"
6400 " if (i == 0) return A();"
6401 " if (i == 1) return B();"
6402 " if (i == 2) return C();"
6406 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6407 ApiTestFuzzer::Fuzz();
6408 if (args.IsConstructCall()) {
6409 args.This()->Set(v8_str("data"), args.Data());
6410 args.GetReturnValue().SetNull();
6413 args.GetReturnValue().Set(args.Data());
6417 class FunctionExtension : public Extension {
6419 FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
6420 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6421 v8::Isolate* isolate, v8::Handle<String> name);
6425 static int lookup_count = 0;
6426 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6427 v8::Isolate* isolate, v8::Handle<String> name) {
6429 if (name->Equals(v8_str("A"))) {
6430 return v8::FunctionTemplate::New(isolate, CallFun,
6431 v8::Integer::New(isolate, 8));
6432 } else if (name->Equals(v8_str("B"))) {
6433 return v8::FunctionTemplate::New(isolate, CallFun,
6434 v8::Integer::New(isolate, 7));
6435 } else if (name->Equals(v8_str("C"))) {
6436 return v8::FunctionTemplate::New(isolate, CallFun,
6437 v8::Integer::New(isolate, 6));
6439 return v8::Handle<v8::FunctionTemplate>();
6444 THREADED_TEST(FunctionLookup) {
6445 v8::RegisterExtension(new FunctionExtension());
6446 v8::HandleScope handle_scope(CcTest::isolate());
6447 static const char* exts[1] = {"functiontest"};
6448 v8::ExtensionConfiguration config(1, exts);
6449 LocalContext context(&config);
6450 CHECK_EQ(3, lookup_count);
6451 CHECK(v8::Integer::New(CcTest::isolate(), 8)->Equals(CompileRun("Foo(0)")));
6452 CHECK(v8::Integer::New(CcTest::isolate(), 7)->Equals(CompileRun("Foo(1)")));
6453 CHECK(v8::Integer::New(CcTest::isolate(), 6)->Equals(CompileRun("Foo(2)")));
6457 THREADED_TEST(NativeFunctionConstructCall) {
6458 v8::RegisterExtension(new FunctionExtension());
6459 v8::HandleScope handle_scope(CcTest::isolate());
6460 static const char* exts[1] = {"functiontest"};
6461 v8::ExtensionConfiguration config(1, exts);
6462 LocalContext context(&config);
6463 for (int i = 0; i < 10; i++) {
6464 // Run a few times to ensure that allocation of objects doesn't
6465 // change behavior of a constructor function.
6466 CHECK(v8::Integer::New(CcTest::isolate(), 8)
6467 ->Equals(CompileRun("(new A()).data")));
6468 CHECK(v8::Integer::New(CcTest::isolate(), 7)
6469 ->Equals(CompileRun("(new B()).data")));
6470 CHECK(v8::Integer::New(CcTest::isolate(), 6)
6471 ->Equals(CompileRun("(new C()).data")));
6476 static const char* last_location;
6477 static const char* last_message;
6478 void StoringErrorCallback(const char* location, const char* message) {
6479 if (last_location == NULL) {
6480 last_location = location;
6481 last_message = message;
6486 // ErrorReporting creates a circular extensions configuration and
6487 // tests that the fatal error handler gets called. This renders V8
6488 // unusable and therefore this test cannot be run in parallel.
6489 TEST(ErrorReporting) {
6490 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
6491 static const char* aDeps[] = {"B"};
6492 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
6493 static const char* bDeps[] = {"A"};
6494 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
6495 last_location = NULL;
6496 v8::ExtensionConfiguration config(1, bDeps);
6497 v8::Handle<Context> context = Context::New(CcTest::isolate(), &config);
6498 CHECK(context.IsEmpty());
6499 CHECK(last_location);
6503 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
6504 v8::Handle<Value> data) {
6505 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
6506 CHECK(v8::Undefined(CcTest::isolate())
6507 ->Equals(message->GetScriptOrigin().ResourceName()));
6508 message->GetLineNumber();
6509 message->GetSourceLine();
6513 THREADED_TEST(ErrorWithMissingScriptInfo) {
6514 LocalContext context;
6515 v8::HandleScope scope(context->GetIsolate());
6516 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
6517 CompileRun("throw Error()");
6518 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
6522 struct FlagAndPersistent {
6524 v8::Global<v8::Object> handle;
6528 static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6529 data.GetParameter()->flag = true;
6530 data.GetParameter()->handle.Reset();
6534 static void IndependentWeakHandle(bool global_gc, bool interlinked) {
6535 v8::Isolate* iso = CcTest::isolate();
6536 v8::HandleScope scope(iso);
6537 v8::Handle<Context> context = Context::New(iso);
6538 Context::Scope context_scope(context);
6540 FlagAndPersistent object_a, object_b;
6542 intptr_t big_heap_size;
6545 v8::HandleScope handle_scope(iso);
6546 Local<Object> a(v8::Object::New(iso));
6547 Local<Object> b(v8::Object::New(iso));
6548 object_a.handle.Reset(iso, a);
6549 object_b.handle.Reset(iso, b);
6551 a->Set(v8_str("x"), b);
6552 b->Set(v8_str("x"), a);
6555 CcTest::heap()->CollectAllGarbage();
6557 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6559 // We are relying on this creating a big flag array and reserving the space
6561 v8::Handle<Value> big_array = CompileRun("new Array(50000)");
6562 a->Set(v8_str("y"), big_array);
6563 big_heap_size = CcTest::heap()->SizeOfObjects();
6566 object_a.flag = false;
6567 object_b.flag = false;
6568 object_a.handle.SetWeak(&object_a, &SetFlag,
6569 v8::WeakCallbackType::kParameter);
6570 object_b.handle.SetWeak(&object_b, &SetFlag,
6571 v8::WeakCallbackType::kParameter);
6572 CHECK(!object_b.handle.IsIndependent());
6573 object_a.handle.MarkIndependent();
6574 object_b.handle.MarkIndependent();
6575 CHECK(object_b.handle.IsIndependent());
6577 CcTest::heap()->CollectAllGarbage();
6579 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6581 // A single GC should be enough to reclaim the memory, since we are using
6583 CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
6584 CHECK(object_a.flag);
6585 CHECK(object_b.flag);
6589 TEST(IndependentWeakHandle) {
6590 IndependentWeakHandle(false, false);
6591 IndependentWeakHandle(false, true);
6592 IndependentWeakHandle(true, false);
6593 IndependentWeakHandle(true, true);
6599 explicit Trivial(int x) : x_(x) {}
6601 int x() { return x_; }
6602 void set_x(int x) { x_ = x; }
6611 Trivial2(int x, int y) : y_(y), x_(x) {}
6613 int x() { return x_; }
6614 void set_x(int x) { x_ = x; }
6616 int y() { return y_; }
6617 void set_y(int y) { y_ = y; }
6625 void CheckInternalFields(
6626 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
6627 v8::Persistent<v8::Object>* handle = data.GetParameter();
6629 Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField1());
6630 Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField2());
6631 CHECK_EQ(42, t1->x());
6632 CHECK_EQ(103, t2->x());
6634 t2->set_x(33550336);
6638 void InternalFieldCallback(bool global_gc) {
6640 v8::Isolate* isolate = env->GetIsolate();
6641 v8::HandleScope scope(isolate);
6643 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
6644 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
6647 instance_templ->SetInternalFieldCount(2);
6649 v8::HandleScope scope(isolate);
6650 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
6651 v8::Persistent<v8::Object> handle(isolate, obj);
6652 CHECK_EQ(2, obj->InternalFieldCount());
6653 CHECK(obj->GetInternalField(0)->IsUndefined());
6654 t1 = new Trivial(42);
6655 t2 = new Trivial2(103, 9);
6657 obj->SetAlignedPointerInInternalField(0, t1);
6658 t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
6659 CHECK_EQ(42, t1->x());
6661 obj->SetAlignedPointerInInternalField(1, t2);
6663 reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
6664 CHECK_EQ(103, t2->x());
6666 handle.SetWeak<v8::Persistent<v8::Object>>(
6667 &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
6669 handle.MarkIndependent();
6673 CcTest::heap()->CollectAllGarbage();
6675 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6678 CHECK_EQ(1729, t1->x());
6679 CHECK_EQ(33550336, t2->x());
6686 THREADED_TEST(InternalFieldCallback) {
6687 InternalFieldCallback(false);
6688 InternalFieldCallback(true);
6692 static void ResetUseValueAndSetFlag(
6693 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6694 // Blink will reset the handle, and then use the other handle, so they
6695 // can't use the same backing slot.
6696 data.GetParameter()->handle.Reset();
6697 data.GetParameter()->flag = true;
6701 static void ResetWeakHandle(bool global_gc) {
6702 v8::Isolate* iso = CcTest::isolate();
6703 v8::HandleScope scope(iso);
6704 v8::Handle<Context> context = Context::New(iso);
6705 Context::Scope context_scope(context);
6707 FlagAndPersistent object_a, object_b;
6710 v8::HandleScope handle_scope(iso);
6711 Local<Object> a(v8::Object::New(iso));
6712 Local<Object> b(v8::Object::New(iso));
6713 object_a.handle.Reset(iso, a);
6714 object_b.handle.Reset(iso, b);
6716 CcTest::heap()->CollectAllGarbage(
6717 TestHeap::Heap::kAbortIncrementalMarkingMask);
6719 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6723 object_a.flag = false;
6724 object_b.flag = false;
6725 object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag,
6726 v8::WeakCallbackType::kParameter);
6727 object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag,
6728 v8::WeakCallbackType::kParameter);
6730 object_a.handle.MarkIndependent();
6731 object_b.handle.MarkIndependent();
6732 CHECK(object_b.handle.IsIndependent());
6735 CcTest::heap()->CollectAllGarbage(
6736 TestHeap::Heap::kAbortIncrementalMarkingMask);
6738 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6740 CHECK(object_a.flag);
6741 CHECK(object_b.flag);
6745 THREADED_TEST(ResetWeakHandle) {
6746 ResetWeakHandle(false);
6747 ResetWeakHandle(true);
6751 static void InvokeScavenge() { CcTest::heap()->CollectGarbage(i::NEW_SPACE); }
6754 static void InvokeMarkSweep() { CcTest::heap()->CollectAllGarbage(); }
6757 static void ForceScavenge2(
6758 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6759 data.GetParameter()->flag = true;
6763 static void ForceScavenge1(
6764 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6765 data.GetParameter()->handle.Reset();
6766 data.SetSecondPassCallback(ForceScavenge2);
6770 static void ForceMarkSweep2(
6771 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6772 data.GetParameter()->flag = true;
6776 static void ForceMarkSweep1(
6777 const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6778 data.GetParameter()->handle.Reset();
6779 data.SetSecondPassCallback(ForceMarkSweep2);
6783 THREADED_TEST(GCFromWeakCallbacks) {
6784 v8::Isolate* isolate = CcTest::isolate();
6785 v8::HandleScope scope(isolate);
6786 v8::Handle<Context> context = Context::New(isolate);
6787 Context::Scope context_scope(context);
6789 static const int kNumberOfGCTypes = 2;
6790 typedef v8::WeakCallbackInfo<FlagAndPersistent>::Callback Callback;
6791 Callback gc_forcing_callback[kNumberOfGCTypes] = {&ForceScavenge1,
6794 typedef void (*GCInvoker)();
6795 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
6797 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
6798 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
6799 FlagAndPersistent object;
6801 v8::HandleScope handle_scope(isolate);
6802 object.handle.Reset(isolate, v8::Object::New(isolate));
6804 object.flag = false;
6805 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc],
6806 v8::WeakCallbackType::kParameter);
6807 object.handle.MarkIndependent();
6808 invoke_gc[outer_gc]();
6815 v8::Handle<Function> args_fun;
6818 static void ArgumentsTestCallback(
6819 const v8::FunctionCallbackInfo<v8::Value>& args) {
6820 ApiTestFuzzer::Fuzz();
6821 v8::Isolate* isolate = args.GetIsolate();
6822 CHECK(args_fun->Equals(args.Callee()));
6823 CHECK_EQ(3, args.Length());
6824 CHECK(v8::Integer::New(isolate, 1)->Equals(args[0]));
6825 CHECK(v8::Integer::New(isolate, 2)->Equals(args[1]));
6826 CHECK(v8::Integer::New(isolate, 3)->Equals(args[2]));
6827 CHECK(v8::Undefined(isolate)->Equals(args[3]));
6828 v8::HandleScope scope(args.GetIsolate());
6829 CcTest::heap()->CollectAllGarbage();
6833 THREADED_TEST(Arguments) {
6834 v8::Isolate* isolate = CcTest::isolate();
6835 v8::HandleScope scope(isolate);
6836 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
6837 global->Set(v8_str("f"),
6838 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
6839 LocalContext context(NULL, global);
6840 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
6841 v8_compile("f(1, 2, 3)")->Run();
6845 static int p_getter_count;
6846 static int p_getter_count2;
6849 static void PGetter(Local<String> name,
6850 const v8::PropertyCallbackInfo<v8::Value>& info) {
6851 ApiTestFuzzer::Fuzz();
6853 v8::Handle<v8::Object> global =
6854 info.GetIsolate()->GetCurrentContext()->Global();
6855 CHECK(info.Holder()->Equals(global->Get(v8_str("o1"))));
6856 if (name->Equals(v8_str("p1"))) {
6857 CHECK(info.This()->Equals(global->Get(v8_str("o1"))));
6858 } else if (name->Equals(v8_str("p2"))) {
6859 CHECK(info.This()->Equals(global->Get(v8_str("o2"))));
6860 } else if (name->Equals(v8_str("p3"))) {
6861 CHECK(info.This()->Equals(global->Get(v8_str("o3"))));
6862 } else if (name->Equals(v8_str("p4"))) {
6863 CHECK(info.This()->Equals(global->Get(v8_str("o4"))));
6868 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
6869 ApiTestFuzzer::Fuzz();
6870 LocalContext context;
6871 context->Global()->Set(v8_str("o1"), obj->NewInstance());
6873 "o1.__proto__ = { };"
6874 "var o2 = { __proto__: o1 };"
6875 "var o3 = { __proto__: o2 };"
6876 "var o4 = { __proto__: o3 };"
6877 "for (var i = 0; i < 10; i++) o4.p4;"
6878 "for (var i = 0; i < 10; i++) o3.p3;"
6879 "for (var i = 0; i < 10; i++) o2.p2;"
6880 "for (var i = 0; i < 10; i++) o1.p1;");
6884 static void PGetter2(Local<Name> name,
6885 const v8::PropertyCallbackInfo<v8::Value>& info) {
6886 ApiTestFuzzer::Fuzz();
6888 v8::Handle<v8::Object> global =
6889 info.GetIsolate()->GetCurrentContext()->Global();
6890 CHECK(info.Holder()->Equals(global->Get(v8_str("o1"))));
6891 if (name->Equals(v8_str("p1"))) {
6892 CHECK(info.This()->Equals(global->Get(v8_str("o1"))));
6893 } else if (name->Equals(v8_str("p2"))) {
6894 CHECK(info.This()->Equals(global->Get(v8_str("o2"))));
6895 } else if (name->Equals(v8_str("p3"))) {
6896 CHECK(info.This()->Equals(global->Get(v8_str("o3"))));
6897 } else if (name->Equals(v8_str("p4"))) {
6898 CHECK(info.This()->Equals(global->Get(v8_str("o4"))));
6903 THREADED_TEST(GetterHolders) {
6904 v8::Isolate* isolate = CcTest::isolate();
6905 v8::HandleScope scope(isolate);
6906 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
6907 obj->SetAccessor(v8_str("p1"), PGetter);
6908 obj->SetAccessor(v8_str("p2"), PGetter);
6909 obj->SetAccessor(v8_str("p3"), PGetter);
6910 obj->SetAccessor(v8_str("p4"), PGetter);
6913 CHECK_EQ(40, p_getter_count);
6917 THREADED_TEST(PreInterceptorHolders) {
6918 v8::Isolate* isolate = CcTest::isolate();
6919 v8::HandleScope scope(isolate);
6920 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
6921 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
6922 p_getter_count2 = 0;
6924 CHECK_EQ(40, p_getter_count2);
6928 THREADED_TEST(ObjectInstantiation) {
6929 v8::Isolate* isolate = CcTest::isolate();
6930 v8::HandleScope scope(isolate);
6931 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
6932 templ->SetAccessor(v8_str("t"), PGetter2);
6933 LocalContext context;
6934 context->Global()->Set(v8_str("o"), templ->NewInstance());
6935 for (int i = 0; i < 100; i++) {
6936 v8::HandleScope inner_scope(CcTest::isolate());
6937 v8::Handle<v8::Object> obj = templ->NewInstance();
6938 CHECK(!obj->Equals(context->Global()->Get(v8_str("o"))));
6939 context->Global()->Set(v8_str("o2"), obj);
6940 v8::Handle<Value> value =
6941 CompileRun("o.__proto__ === o2.__proto__");
6942 CHECK(v8::True(isolate)->Equals(value));
6943 context->Global()->Set(v8_str("o"), obj);
6948 static int StrCmp16(uint16_t* a, uint16_t* b) {
6950 if (*a == 0 && *b == 0) return 0;
6951 if (*a != *b) return 0 + *a - *b;
6958 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
6960 if (n-- == 0) return 0;
6961 if (*a == 0 && *b == 0) return 0;
6962 if (*a != *b) return 0 + *a - *b;
6969 int GetUtf8Length(Handle<String> str) {
6970 int len = str->Utf8Length();
6972 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
6973 i::String::Flatten(istr);
6974 len = str->Utf8Length();
6980 THREADED_TEST(StringWrite) {
6981 LocalContext context;
6982 v8::HandleScope scope(context->GetIsolate());
6983 v8::Handle<String> str = v8_str("abcde");
6984 // abc<Icelandic eth><Unicode snowman>.
6985 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
6986 v8::Handle<String> str3 = v8::String::NewFromUtf8(
6987 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
6988 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
6989 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
6990 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
6991 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
6992 // single lead surrogate
6993 uint16_t lead[1] = { 0xd800 };
6994 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
6995 context->GetIsolate(), lead, v8::String::kNormalString, 1);
6996 // single trail surrogate
6997 uint16_t trail[1] = { 0xdc00 };
6998 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
6999 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7001 uint16_t pair[2] = { 0xd800, 0xdc00 };
7002 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7003 context->GetIsolate(), pair, v8::String::kNormalString, 2);
7004 const int kStride = 4; // Must match stride in for loops in JS below.
7007 "for (var i = 0; i < 0xd800; i += 4) {"
7008 " left = left + String.fromCharCode(i);"
7012 "for (var i = 0; i < 0xd800; i += 4) {"
7013 " right = String.fromCharCode(i) + right;"
7015 v8::Handle<v8::Object> global = context->Global();
7016 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7017 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7019 CHECK_EQ(5, str2->Length());
7020 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7021 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7024 char utf8buf[0xd800 * 3];
7029 memset(utf8buf, 0x1, 1000);
7030 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7032 CHECK_EQ(5, charlen);
7033 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7035 memset(utf8buf, 0x1, 1000);
7036 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7038 CHECK_EQ(5, charlen);
7039 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7041 memset(utf8buf, 0x1, 1000);
7042 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7044 CHECK_EQ(4, charlen);
7045 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7047 memset(utf8buf, 0x1, 1000);
7048 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7050 CHECK_EQ(4, charlen);
7051 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7053 memset(utf8buf, 0x1, 1000);
7054 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7056 CHECK_EQ(4, charlen);
7057 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7059 memset(utf8buf, 0x1, 1000);
7060 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7062 CHECK_EQ(3, charlen);
7063 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7065 memset(utf8buf, 0x1, 1000);
7066 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7068 CHECK_EQ(3, charlen);
7069 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7071 memset(utf8buf, 0x1, 1000);
7072 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7074 CHECK_EQ(2, charlen);
7075 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7077 // allow orphan surrogates by default
7078 memset(utf8buf, 0x1, 1000);
7079 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7081 CHECK_EQ(8, charlen);
7082 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7084 // replace orphan surrogates with unicode replacement character
7085 memset(utf8buf, 0x1, 1000);
7086 len = orphans_str->WriteUtf8(utf8buf,
7089 String::REPLACE_INVALID_UTF8);
7091 CHECK_EQ(8, charlen);
7092 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7094 // replace single lead surrogate with unicode replacement character
7095 memset(utf8buf, 0x1, 1000);
7096 len = lead_str->WriteUtf8(utf8buf,
7099 String::REPLACE_INVALID_UTF8);
7101 CHECK_EQ(1, charlen);
7102 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7104 // replace single trail surrogate with unicode replacement character
7105 memset(utf8buf, 0x1, 1000);
7106 len = trail_str->WriteUtf8(utf8buf,
7109 String::REPLACE_INVALID_UTF8);
7111 CHECK_EQ(1, charlen);
7112 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7114 // do not replace / write anything if surrogate pair does not fit the buffer
7116 memset(utf8buf, 0x1, 1000);
7117 len = pair_str->WriteUtf8(utf8buf,
7120 String::REPLACE_INVALID_UTF8);
7122 CHECK_EQ(0, charlen);
7124 memset(utf8buf, 0x1, sizeof(utf8buf));
7125 len = GetUtf8Length(left_tree);
7127 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7128 CHECK_EQ(utf8_expected, len);
7129 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7130 CHECK_EQ(utf8_expected, len);
7131 CHECK_EQ(0xd800 / kStride, charlen);
7132 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7133 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7134 CHECK_EQ(0xc0 - kStride,
7135 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7136 CHECK_EQ(1, utf8buf[utf8_expected]);
7138 memset(utf8buf, 0x1, sizeof(utf8buf));
7139 len = GetUtf8Length(right_tree);
7140 CHECK_EQ(utf8_expected, len);
7141 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7142 CHECK_EQ(utf8_expected, len);
7143 CHECK_EQ(0xd800 / kStride, charlen);
7144 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7145 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7146 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7147 CHECK_EQ(1, utf8buf[utf8_expected]);
7149 memset(buf, 0x1, sizeof(buf));
7150 memset(wbuf, 0x1, sizeof(wbuf));
7151 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7153 len = str->Write(wbuf);
7155 CHECK_EQ(0, strcmp("abcde", buf));
7156 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7157 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7159 memset(buf, 0x1, sizeof(buf));
7160 memset(wbuf, 0x1, sizeof(wbuf));
7161 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7163 len = str->Write(wbuf, 0, 4);
7165 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7166 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7167 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7169 memset(buf, 0x1, sizeof(buf));
7170 memset(wbuf, 0x1, sizeof(wbuf));
7171 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7173 len = str->Write(wbuf, 0, 5);
7175 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7176 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7177 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7179 memset(buf, 0x1, sizeof(buf));
7180 memset(wbuf, 0x1, sizeof(wbuf));
7181 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7183 len = str->Write(wbuf, 0, 6);
7185 CHECK_EQ(0, strcmp("abcde", buf));
7186 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7187 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7189 memset(buf, 0x1, sizeof(buf));
7190 memset(wbuf, 0x1, sizeof(wbuf));
7191 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7193 len = str->Write(wbuf, 4, -1);
7195 CHECK_EQ(0, strcmp("e", buf));
7196 uint16_t answer5[] = {'e', '\0'};
7197 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7199 memset(buf, 0x1, sizeof(buf));
7200 memset(wbuf, 0x1, sizeof(wbuf));
7201 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7203 len = str->Write(wbuf, 4, 6);
7205 CHECK_EQ(0, strcmp("e", buf));
7206 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7208 memset(buf, 0x1, sizeof(buf));
7209 memset(wbuf, 0x1, sizeof(wbuf));
7210 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7212 len = str->Write(wbuf, 4, 1);
7214 CHECK_EQ(0, strncmp("e\1", buf, 2));
7215 uint16_t answer6[] = {'e', 0x101};
7216 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7218 memset(buf, 0x1, sizeof(buf));
7219 memset(wbuf, 0x1, sizeof(wbuf));
7220 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7222 len = str->Write(wbuf, 3, 1);
7224 CHECK_EQ(0, strncmp("d\1", buf, 2));
7225 uint16_t answer7[] = {'d', 0x101};
7226 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7228 memset(wbuf, 0x1, sizeof(wbuf));
7230 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7232 CHECK_EQ('X', wbuf[5]);
7233 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7234 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7235 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7236 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7238 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7240 memset(buf, 0x1, sizeof(buf));
7242 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7245 String::NO_NULL_TERMINATION);
7247 CHECK_EQ('X', buf[5]);
7248 CHECK_EQ(0, strncmp("abcde", buf, 5));
7249 CHECK_NE(0, strcmp("abcde", buf));
7251 CHECK_EQ(0, strcmp("abcde", buf));
7253 memset(utf8buf, 0x1, sizeof(utf8buf));
7255 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7256 String::NO_NULL_TERMINATION);
7258 CHECK_EQ('X', utf8buf[8]);
7259 CHECK_EQ(5, charlen);
7260 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7261 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7263 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7265 memset(utf8buf, 0x1, sizeof(utf8buf));
7267 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7268 String::NO_NULL_TERMINATION);
7270 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7271 CHECK_EQ(5, charlen);
7273 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7275 memset(buf, 0x1, sizeof(buf));
7276 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7278 CHECK_EQ(0, strcmp("abc", buf));
7279 CHECK_EQ(0, buf[3]);
7280 CHECK_EQ(0, strcmp("def", buf + 4));
7282 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7283 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7284 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7288 static void Utf16Helper(
7289 LocalContext& context, // NOLINT
7291 const char* lengths_name,
7293 Local<v8::Array> a =
7294 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7295 Local<v8::Array> alens =
7296 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7297 for (int i = 0; i < len; i++) {
7298 Local<v8::String> string =
7299 Local<v8::String>::Cast(a->Get(i));
7300 Local<v8::Number> expected_len =
7301 Local<v8::Number>::Cast(alens->Get(i));
7302 int length = GetUtf8Length(string);
7303 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7308 THREADED_TEST(Utf16) {
7309 LocalContext context;
7310 v8::HandleScope scope(context->GetIsolate());
7312 "var pad = '01234567890123456789';"
7314 "var plens = [20, 3, 3];"
7315 "p.push('01234567890123456789');"
7316 "var lead = 0xd800;"
7317 "var trail = 0xdc00;"
7318 "p.push(String.fromCharCode(0xd800));"
7319 "p.push(String.fromCharCode(0xdc00));"
7324 "for (var i = 0; i < 3; i++) {"
7325 " p[1] = String.fromCharCode(lead++);"
7326 " for (var j = 0; j < 3; j++) {"
7327 " p[2] = String.fromCharCode(trail++);"
7328 " a.push(p[i] + p[j]);"
7329 " b.push(p[i] + p[j]);"
7330 " c.push(p[i] + p[j]);"
7331 " alens.push(plens[i] + plens[j]);"
7334 "alens[5] -= 2;" // Here the surrogate pairs match up.
7339 "for (var m = 0; m < 9; m++) {"
7340 " for (var n = 0; n < 9; n++) {"
7341 " a2.push(a[m] + a[n]);"
7342 " b2.push(b[m] + b[n]);"
7343 " var newc = 'x' + c[m] + c[n] + 'y';"
7344 " c2.push(newc.substring(1, newc.length - 1));"
7345 " var utf = alens[m] + alens[n];" // And here.
7346 // The 'n's that start with 0xdc.. are 6-8
7347 // The 'm's that end with 0xd8.. are 1, 4 and 7
7348 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
7349 " a2lens.push(utf);"
7352 Utf16Helper(context, "a", "alens", 9);
7353 Utf16Helper(context, "a2", "a2lens", 81);
7357 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7358 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7359 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7360 return *is1 == *is2;
7364 THREADED_TEST(Utf16Symbol) {
7365 LocalContext context;
7366 v8::HandleScope scope(context->GetIsolate());
7368 Handle<String> symbol1 = v8::String::NewFromUtf8(
7369 context->GetIsolate(), "abc", v8::String::kInternalizedString);
7370 Handle<String> symbol2 = v8::String::NewFromUtf8(
7371 context->GetIsolate(), "abc", v8::String::kInternalizedString);
7372 CHECK(SameSymbol(symbol1, symbol2));
7375 "var sym0 = 'benedictus';"
7376 "var sym0b = 'S\303\270ren';"
7377 "var sym1 = '\355\240\201\355\260\207';"
7378 "var sym2 = '\360\220\220\210';"
7379 "var sym3 = 'x\355\240\201\355\260\207';"
7380 "var sym4 = 'x\360\220\220\210';"
7381 "if (sym1.length != 2) throw sym1;"
7382 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
7383 "if (sym2.length != 2) throw sym2;"
7384 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
7385 "if (sym3.length != 3) throw sym3;"
7386 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
7387 "if (sym4.length != 3) throw sym4;"
7388 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
7389 Handle<String> sym0 = v8::String::NewFromUtf8(
7390 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
7391 Handle<String> sym0b = v8::String::NewFromUtf8(
7392 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
7393 Handle<String> sym1 =
7394 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
7395 v8::String::kInternalizedString);
7396 Handle<String> sym2 =
7397 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
7398 v8::String::kInternalizedString);
7399 Handle<String> sym3 = v8::String::NewFromUtf8(
7400 context->GetIsolate(), "x\355\240\201\355\260\207",
7401 v8::String::kInternalizedString);
7402 Handle<String> sym4 =
7403 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
7404 v8::String::kInternalizedString);
7405 v8::Local<v8::Object> global = context->Global();
7406 Local<Value> s0 = global->Get(v8_str("sym0"));
7407 Local<Value> s0b = global->Get(v8_str("sym0b"));
7408 Local<Value> s1 = global->Get(v8_str("sym1"));
7409 Local<Value> s2 = global->Get(v8_str("sym2"));
7410 Local<Value> s3 = global->Get(v8_str("sym3"));
7411 Local<Value> s4 = global->Get(v8_str("sym4"));
7412 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
7413 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
7414 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
7415 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
7416 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
7417 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
7421 THREADED_TEST(Utf16MissingTrailing) {
7422 LocalContext context;
7423 v8::HandleScope scope(context->GetIsolate());
7425 // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
7426 int size = 1024 * 64;
7427 uint8_t* buffer = new uint8_t[size];
7428 for (int i = 0; i < size; i += 4) {
7430 buffer[i + 1] = 0x9d;
7431 buffer[i + 2] = 0x80;
7432 buffer[i + 3] = 0x9e;
7435 // Now invoke the decoder without last 3 bytes
7436 v8::Local<v8::String> str =
7437 v8::String::NewFromUtf8(
7438 context->GetIsolate(), reinterpret_cast<char*>(buffer),
7439 v8::NewStringType::kNormal, size - 3).ToLocalChecked();
7445 THREADED_TEST(Utf16Trailing3Byte) {
7446 LocalContext context;
7447 v8::HandleScope scope(context->GetIsolate());
7449 // Make sure it will go past the buffer, so it will call `WriteUtf16Slow`
7450 int size = 1024 * 63;
7451 uint8_t* buffer = new uint8_t[size];
7452 for (int i = 0; i < size; i += 3) {
7454 buffer[i + 1] = 0x80;
7455 buffer[i + 2] = 0xa6;
7458 // Now invoke the decoder without last 3 bytes
7459 v8::Local<v8::String> str =
7460 v8::String::NewFromUtf8(
7461 context->GetIsolate(), reinterpret_cast<char*>(buffer),
7462 v8::NewStringType::kNormal, size).ToLocalChecked();
7464 v8::String::Value value(str);
7465 CHECK_EQ(value.length(), size / 3);
7466 CHECK_EQ((*value)[value.length() - 1], 0x2026);
7472 THREADED_TEST(ToArrayIndex) {
7473 LocalContext context;
7474 v8::Isolate* isolate = context->GetIsolate();
7475 v8::HandleScope scope(isolate);
7477 v8::Handle<String> str = v8_str("42");
7478 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
7479 CHECK(!index.IsEmpty());
7480 CHECK_EQ(42.0, index->Uint32Value());
7481 str = v8_str("42asdf");
7482 index = str->ToArrayIndex();
7483 CHECK(index.IsEmpty());
7484 str = v8_str("-42");
7485 index = str->ToArrayIndex();
7486 CHECK(index.IsEmpty());
7487 str = v8_str("4294967294");
7488 index = str->ToArrayIndex();
7489 CHECK(!index.IsEmpty());
7490 CHECK_EQ(4294967294.0, index->Uint32Value());
7491 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
7492 index = num->ToArrayIndex();
7493 CHECK(!index.IsEmpty());
7494 CHECK_EQ(1.0, index->Uint32Value());
7495 num = v8::Number::New(isolate, -1);
7496 index = num->ToArrayIndex();
7497 CHECK(index.IsEmpty());
7498 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
7499 index = obj->ToArrayIndex();
7500 CHECK(index.IsEmpty());
7504 THREADED_TEST(ErrorConstruction) {
7505 LocalContext context;
7506 v8::HandleScope scope(context->GetIsolate());
7508 v8::Handle<String> foo = v8_str("foo");
7509 v8::Handle<String> message = v8_str("message");
7510 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
7511 CHECK(range_error->IsObject());
7512 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
7513 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
7514 CHECK(reference_error->IsObject());
7515 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
7516 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
7517 CHECK(syntax_error->IsObject());
7518 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
7519 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
7520 CHECK(type_error->IsObject());
7521 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
7522 v8::Handle<Value> error = v8::Exception::Error(foo);
7523 CHECK(error->IsObject());
7524 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7528 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
7529 ApiTestFuzzer::Fuzz();
7530 v8::Handle<String> foo = v8_str("foo");
7531 v8::Handle<String> message = v8_str("message");
7532 v8::Handle<Value> error = v8::Exception::Error(foo);
7533 CHECK(error->IsObject());
7534 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7535 info.GetIsolate()->ThrowException(error);
7536 info.GetReturnValue().SetUndefined();
7540 THREADED_TEST(ExceptionCreateMessage) {
7541 LocalContext context;
7542 v8::HandleScope scope(context->GetIsolate());
7543 v8::Handle<String> foo_str = v8_str("foo");
7544 v8::Handle<String> message_str = v8_str("message");
7546 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
7548 Local<v8::FunctionTemplate> fun =
7549 v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
7550 v8::Local<v8::Object> global = context->Global();
7551 global->Set(v8_str("throwV8Exception"), fun->GetFunction());
7553 TryCatch try_catch(context->GetIsolate());
7556 " throwV8Exception();\n"
7559 CHECK(try_catch.HasCaught());
7561 v8::Handle<v8::Value> error = try_catch.Exception();
7562 CHECK(error->IsObject());
7563 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
7565 v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
7566 CHECK(!message.IsEmpty());
7567 CHECK_EQ(2, message->GetLineNumber());
7568 CHECK_EQ(2, message->GetStartColumn());
7570 v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
7571 CHECK(!stackTrace.IsEmpty());
7572 CHECK_EQ(2, stackTrace->GetFrameCount());
7574 stackTrace = v8::Exception::GetStackTrace(error);
7575 CHECK(!stackTrace.IsEmpty());
7576 CHECK_EQ(2, stackTrace->GetFrameCount());
7578 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
7580 // Now check message location when SetCaptureStackTraceForUncaughtExceptions
7586 " return throwV8Exception();\n"
7589 CHECK(try_catch.HasCaught());
7591 error = try_catch.Exception();
7592 CHECK(error->IsObject());
7593 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
7595 message = v8::Exception::CreateMessage(error);
7596 CHECK(!message.IsEmpty());
7597 CHECK_EQ(2, message->GetLineNumber());
7598 CHECK_EQ(9, message->GetStartColumn());
7600 // Should be empty stack trace.
7601 stackTrace = message->GetStackTrace();
7602 CHECK(stackTrace.IsEmpty());
7603 CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
7607 THREADED_TEST(ExceptionCreateMessageLength) {
7608 LocalContext context;
7609 v8::HandleScope scope(context->GetIsolate());
7611 // Test that the message is not truncated.
7612 TryCatch try_catch(context->GetIsolate());
7614 "var message = 'm';"
7615 "while (message.length < 1000) message += message;"
7617 CHECK(try_catch.HasCaught());
7619 CHECK_LT(1000, try_catch.Message()->Get()->Length());
7623 static void YGetter(Local<String> name,
7624 const v8::PropertyCallbackInfo<v8::Value>& info) {
7625 ApiTestFuzzer::Fuzz();
7626 info.GetReturnValue().Set(v8_num(10));
7630 static void YSetter(Local<String> name,
7632 const v8::PropertyCallbackInfo<void>& info) {
7633 Local<Object> this_obj = Local<Object>::Cast(info.This());
7634 if (this_obj->Has(name)) this_obj->Delete(name);
7635 this_obj->Set(name, value);
7639 THREADED_TEST(DeleteAccessor) {
7640 v8::Isolate* isolate = CcTest::isolate();
7641 v8::HandleScope scope(isolate);
7642 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7643 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
7644 LocalContext context;
7645 v8::Handle<v8::Object> holder = obj->NewInstance();
7646 context->Global()->Set(v8_str("holder"), holder);
7647 v8::Handle<Value> result = CompileRun(
7648 "holder.y = 11; holder.y = 12; holder.y");
7649 CHECK_EQ(12u, result->Uint32Value());
7653 THREADED_TEST(TypeSwitch) {
7654 v8::Isolate* isolate = CcTest::isolate();
7655 v8::HandleScope scope(isolate);
7656 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
7657 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
7658 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
7659 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
7660 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
7661 LocalContext context;
7662 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
7663 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
7664 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
7665 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
7666 for (int i = 0; i < 10; i++) {
7667 CHECK_EQ(0, type_switch->match(obj0));
7668 CHECK_EQ(1, type_switch->match(obj1));
7669 CHECK_EQ(2, type_switch->match(obj2));
7670 CHECK_EQ(3, type_switch->match(obj3));
7671 CHECK_EQ(3, type_switch->match(obj3));
7672 CHECK_EQ(2, type_switch->match(obj2));
7673 CHECK_EQ(1, type_switch->match(obj1));
7674 CHECK_EQ(0, type_switch->match(obj0));
7679 static int trouble_nesting = 0;
7680 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7681 ApiTestFuzzer::Fuzz();
7684 // Call a JS function that throws an uncaught exception.
7685 Local<v8::Object> arg_this =
7686 args.GetIsolate()->GetCurrentContext()->Global();
7687 Local<Value> trouble_callee = (trouble_nesting == 3) ?
7688 arg_this->Get(v8_str("trouble_callee")) :
7689 arg_this->Get(v8_str("trouble_caller"));
7690 CHECK(trouble_callee->IsFunction());
7691 args.GetReturnValue().Set(
7692 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
7696 static int report_count = 0;
7697 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
7698 v8::Handle<Value>) {
7703 // Counts uncaught exceptions, but other tests running in parallel
7704 // also have uncaught exceptions.
7705 TEST(ApiUncaughtException) {
7708 v8::Isolate* isolate = env->GetIsolate();
7709 v8::HandleScope scope(isolate);
7710 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7712 Local<v8::FunctionTemplate> fun =
7713 v8::FunctionTemplate::New(isolate, TroubleCallback);
7714 v8::Local<v8::Object> global = env->Global();
7715 global->Set(v8_str("trouble"), fun->GetFunction());
7718 "function trouble_callee() {"
7722 "function trouble_caller() {"
7725 Local<Value> trouble = global->Get(v8_str("trouble"));
7726 CHECK(trouble->IsFunction());
7727 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
7728 CHECK(trouble_callee->IsFunction());
7729 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
7730 CHECK(trouble_caller->IsFunction());
7731 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
7732 CHECK_EQ(1, report_count);
7733 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7737 TEST(ApiUncaughtExceptionInObjectObserve) {
7738 v8::internal::FLAG_stack_size = 150;
7741 v8::Isolate* isolate = env->GetIsolate();
7742 v8::HandleScope scope(isolate);
7743 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7746 "var observe_count = 0;"
7747 "function observer1() { ++observe_count; };"
7748 "function observer2() { ++observe_count; };"
7749 "function observer_throws() { throw new Error(); };"
7750 "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
7751 "Object.observe(obj, observer_throws.bind());"
7752 "Object.observe(obj, observer1);"
7753 "Object.observe(obj, stack_overflow);"
7754 "Object.observe(obj, observer2);"
7755 "Object.observe(obj, observer_throws.bind());"
7756 "obj.foo = 'bar';");
7757 CHECK_EQ(3, report_count);
7758 ExpectInt32("observe_count", 2);
7759 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7763 static const char* script_resource_name = "ExceptionInNativeScript.js";
7764 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
7765 v8::Handle<Value>) {
7766 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
7767 CHECK(!name_val.IsEmpty() && name_val->IsString());
7768 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
7769 CHECK_EQ(0, strcmp(script_resource_name, *name));
7770 CHECK_EQ(3, message->GetLineNumber());
7771 v8::String::Utf8Value source_line(message->GetSourceLine());
7772 CHECK_EQ(0, strcmp(" new o.foo();", *source_line));
7776 TEST(ExceptionInNativeScript) {
7778 v8::Isolate* isolate = env->GetIsolate();
7779 v8::HandleScope scope(isolate);
7780 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
7782 Local<v8::FunctionTemplate> fun =
7783 v8::FunctionTemplate::New(isolate, TroubleCallback);
7784 v8::Local<v8::Object> global = env->Global();
7785 global->Set(v8_str("trouble"), fun->GetFunction());
7787 CompileRunWithOrigin(
7788 "function trouble() {\n"
7792 script_resource_name);
7793 Local<Value> trouble = global->Get(v8_str("trouble"));
7794 CHECK(trouble->IsFunction());
7795 Function::Cast(*trouble)->Call(global, 0, NULL);
7796 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
7800 TEST(CompilationErrorUsingTryCatchHandler) {
7802 v8::HandleScope scope(env->GetIsolate());
7803 v8::TryCatch try_catch(env->GetIsolate());
7804 v8_compile("This doesn't &*&@#$&*^ compile.");
7805 CHECK(*try_catch.Exception());
7806 CHECK(try_catch.HasCaught());
7810 TEST(TryCatchFinallyUsingTryCatchHandler) {
7812 v8::HandleScope scope(env->GetIsolate());
7813 v8::TryCatch try_catch(env->GetIsolate());
7814 CompileRun("try { throw ''; } catch (e) {}");
7815 CHECK(!try_catch.HasCaught());
7816 CompileRun("try { throw ''; } finally {}");
7817 CHECK(try_catch.HasCaught());
7821 "try { throw ''; } finally { return; }"
7823 CHECK(!try_catch.HasCaught());
7826 " { try { throw ''; } finally { throw 0; }"
7828 CHECK(try_catch.HasCaught());
7832 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
7833 v8::HandleScope scope(args.GetIsolate());
7834 CompileRun(args[0]->ToString(args.GetIsolate()));
7838 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
7839 v8::Isolate* isolate = CcTest::isolate();
7840 v8::HandleScope scope(isolate);
7841 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7842 templ->Set(v8_str("CEvaluate"),
7843 v8::FunctionTemplate::New(isolate, CEvaluate));
7844 LocalContext context(0, templ);
7845 v8::TryCatch try_catch(isolate);
7847 " CEvaluate('throw 1;');"
7850 CHECK(try_catch.HasCaught());
7851 CHECK(!try_catch.Message().IsEmpty());
7852 String::Utf8Value exception_value(try_catch.Exception());
7853 CHECK_EQ(0, strcmp(*exception_value, "1"));
7856 " CEvaluate('throw 1;');"
7860 CHECK(try_catch.HasCaught());
7861 CHECK(!try_catch.Message().IsEmpty());
7862 String::Utf8Value finally_exception_value(try_catch.Exception());
7863 CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
7867 // For use within the TestSecurityHandler() test.
7868 static bool g_security_callback_result = false;
7869 static bool SecurityTestCallback(Local<v8::Object> global, Local<Value> name,
7870 v8::AccessType type, Local<Value> data) {
7872 return g_security_callback_result;
7876 // SecurityHandler can't be run twice
7877 TEST(SecurityHandler) {
7878 v8::Isolate* isolate = CcTest::isolate();
7879 v8::HandleScope scope0(isolate);
7880 v8::Handle<v8::ObjectTemplate> global_template =
7881 v8::ObjectTemplate::New(isolate);
7882 global_template->SetAccessCheckCallbacks(SecurityTestCallback, NULL);
7883 // Create an environment
7884 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
7887 v8::Handle<v8::Object> global0 = context0->Global();
7888 v8::Handle<Script> script0 = v8_compile("foo = 111");
7890 global0->Set(v8_str("0"), v8_num(999));
7891 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
7892 CHECK_EQ(111, foo0->Int32Value());
7893 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
7894 CHECK_EQ(999, z0->Int32Value());
7896 // Create another environment, should fail security checks.
7897 v8::HandleScope scope1(isolate);
7899 v8::Handle<Context> context1 =
7900 Context::New(isolate, NULL, global_template);
7903 v8::Handle<v8::Object> global1 = context1->Global();
7904 global1->Set(v8_str("othercontext"), global0);
7905 // This set will fail the security check.
7906 v8::Handle<Script> script1 =
7907 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
7909 g_security_callback_result = true;
7910 // This read will pass the security check.
7911 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
7912 CHECK_EQ(111, foo1->Int32Value());
7913 // This read will pass the security check.
7914 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
7915 CHECK_EQ(999, z1->Int32Value());
7917 // Create another environment, should pass security checks.
7919 v8::HandleScope scope2(isolate);
7920 LocalContext context2;
7921 v8::Handle<v8::Object> global2 = context2->Global();
7922 global2->Set(v8_str("othercontext"), global0);
7923 v8::Handle<Script> script2 =
7924 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
7926 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
7927 CHECK_EQ(333, foo2->Int32Value());
7928 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
7929 CHECK_EQ(888, z2->Int32Value());
7937 THREADED_TEST(SecurityChecks) {
7939 v8::HandleScope handle_scope(env1->GetIsolate());
7940 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7942 Local<Value> foo = v8_str("foo");
7943 Local<Value> bar = v8_str("bar");
7945 // Set to the same domain.
7946 env1->SetSecurityToken(foo);
7948 // Create a function in env1.
7949 CompileRun("spy=function(){return spy;}");
7950 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
7951 CHECK(spy->IsFunction());
7953 // Create another function accessing global objects.
7954 CompileRun("spy2=function(){return new this.Array();}");
7955 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
7956 CHECK(spy2->IsFunction());
7958 // Switch to env2 in the same domain and invoke spy on env2.
7960 env2->SetSecurityToken(foo);
7962 Context::Scope scope_env2(env2);
7963 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
7964 CHECK(result->IsFunction());
7968 env2->SetSecurityToken(bar);
7969 Context::Scope scope_env2(env2);
7971 // Call cross_domain_call, it should throw an exception
7972 v8::TryCatch try_catch(env1->GetIsolate());
7973 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
7974 CHECK(try_catch.HasCaught());
7979 // Regression test case for issue 1183439.
7980 THREADED_TEST(SecurityChecksForPrototypeChain) {
7981 LocalContext current;
7982 v8::HandleScope scope(current->GetIsolate());
7983 v8::Handle<Context> other = Context::New(current->GetIsolate());
7985 // Change context to be able to get to the Object function in the
7986 // other context without hitting the security checks.
7987 v8::Local<Value> other_object;
7988 { Context::Scope scope(other);
7989 other_object = other->Global()->Get(v8_str("Object"));
7990 other->Global()->Set(v8_num(42), v8_num(87));
7993 current->Global()->Set(v8_str("other"), other->Global());
7994 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
7996 // Make sure the security check fails here and we get an undefined
7997 // result instead of getting the Object function. Repeat in a loop
7998 // to make sure to exercise the IC code.
7999 v8::Local<Script> access_other0 = v8_compile("other.Object");
8000 v8::Local<Script> access_other1 = v8_compile("other[42]");
8001 for (int i = 0; i < 5; i++) {
8002 CHECK(access_other0->Run().IsEmpty());
8003 CHECK(access_other1->Run().IsEmpty());
8006 // Create an object that has 'other' in its prototype chain and make
8007 // sure we cannot access the Object function indirectly through
8008 // that. Repeat in a loop to make sure to exercise the IC code.
8009 v8_compile("function F() { };"
8010 "F.prototype = other;"
8011 "var f = new F();")->Run();
8012 v8::Local<Script> access_f0 = v8_compile("f.Object");
8013 v8::Local<Script> access_f1 = v8_compile("f[42]");
8014 for (int j = 0; j < 5; j++) {
8015 CHECK(access_f0->Run().IsEmpty());
8016 CHECK(access_f1->Run().IsEmpty());
8019 // Now it gets hairy: Set the prototype for the other global object
8020 // to be the current global object. The prototype chain for 'f' now
8021 // goes through 'other' but ends up in the current global object.
8022 { Context::Scope scope(other);
8023 other->Global()->Set(v8_str("__proto__"), current->Global());
8025 // Set a named and an index property on the current global
8026 // object. To force the lookup to go through the other global object,
8027 // the properties must not exist in the other global object.
8028 current->Global()->Set(v8_str("foo"), v8_num(100));
8029 current->Global()->Set(v8_num(99), v8_num(101));
8030 // Try to read the properties from f and make sure that the access
8031 // gets stopped by the security checks on the other global object.
8032 Local<Script> access_f2 = v8_compile("f.foo");
8033 Local<Script> access_f3 = v8_compile("f[99]");
8034 for (int k = 0; k < 5; k++) {
8035 CHECK(access_f2->Run().IsEmpty());
8036 CHECK(access_f3->Run().IsEmpty());
8041 static bool security_check_with_gc_called;
8043 static bool SecurityTestCallbackWithGC(Local<v8::Object> global,
8044 Local<v8::Value> name,
8045 v8::AccessType type, Local<Value> data) {
8046 CcTest::heap()->CollectAllGarbage();
8047 security_check_with_gc_called = true;
8052 TEST(SecurityTestGCAllowed) {
8053 v8::Isolate* isolate = CcTest::isolate();
8054 v8::HandleScope handle_scope(isolate);
8055 v8::Handle<v8::ObjectTemplate> object_template =
8056 v8::ObjectTemplate::New(isolate);
8057 object_template->SetAccessCheckCallbacks(SecurityTestCallbackWithGC, NULL);
8059 v8::Handle<Context> context = Context::New(isolate);
8060 v8::Context::Scope context_scope(context);
8062 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8064 security_check_with_gc_called = false;
8065 CompileRun("obj[0] = new String(1002);");
8066 CHECK(security_check_with_gc_called);
8068 security_check_with_gc_called = false;
8069 CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
8070 CHECK(security_check_with_gc_called);
8074 THREADED_TEST(CrossDomainDelete) {
8076 v8::HandleScope handle_scope(env1->GetIsolate());
8077 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8079 Local<Value> foo = v8_str("foo");
8080 Local<Value> bar = v8_str("bar");
8082 // Set to the same domain.
8083 env1->SetSecurityToken(foo);
8084 env2->SetSecurityToken(foo);
8086 env1->Global()->Set(v8_str("prop"), v8_num(3));
8087 env2->Global()->Set(v8_str("env1"), env1->Global());
8089 // Change env2 to a different domain and delete env1.prop.
8090 env2->SetSecurityToken(bar);
8092 Context::Scope scope_env2(env2);
8093 Local<Value> result =
8094 CompileRun("delete env1.prop");
8095 CHECK(result.IsEmpty());
8098 // Check that env1.prop still exists.
8099 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8100 CHECK(v->IsNumber());
8101 CHECK_EQ(3, v->Int32Value());
8105 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8107 v8::HandleScope handle_scope(env1->GetIsolate());
8108 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8110 Local<Value> foo = v8_str("foo");
8111 Local<Value> bar = v8_str("bar");
8113 // Set to the same domain.
8114 env1->SetSecurityToken(foo);
8115 env2->SetSecurityToken(foo);
8117 env1->Global()->Set(v8_str("prop"), v8_num(3));
8118 env2->Global()->Set(v8_str("env1"), env1->Global());
8120 // env1.prop is enumerable in env2.
8121 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8123 Context::Scope scope_env2(env2);
8124 Local<Value> result = CompileRun(test);
8125 CHECK(result->IsTrue());
8128 // Change env2 to a different domain and test again.
8129 env2->SetSecurityToken(bar);
8131 Context::Scope scope_env2(env2);
8132 Local<Value> result = CompileRun(test);
8133 CHECK(result.IsEmpty());
8138 THREADED_TEST(CrossDomainForIn) {
8140 v8::HandleScope handle_scope(env1->GetIsolate());
8141 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8143 Local<Value> foo = v8_str("foo");
8144 Local<Value> bar = v8_str("bar");
8146 // Set to the same domain.
8147 env1->SetSecurityToken(foo);
8148 env2->SetSecurityToken(foo);
8150 env1->Global()->Set(v8_str("prop"), v8_num(3));
8151 env2->Global()->Set(v8_str("env1"), env1->Global());
8153 // Change env2 to a different domain and set env1's global object
8154 // as the __proto__ of an object in env2 and enumerate properties
8155 // in for-in. It shouldn't enumerate properties on env1's global
8157 env2->SetSecurityToken(bar);
8159 Context::Scope scope_env2(env2);
8160 Local<Value> result = CompileRun(
8162 " var obj = { '__proto__': env1 };"
8164 " for (var p in obj) {"
8165 " if (p == 'prop') return false;"
8172 CHECK(result->IsTrue());
8177 TEST(ContextDetachGlobal) {
8179 v8::HandleScope handle_scope(env1->GetIsolate());
8180 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8182 Local<v8::Object> global1 = env1->Global();
8184 Local<Value> foo = v8_str("foo");
8186 // Set to the same domain.
8187 env1->SetSecurityToken(foo);
8188 env2->SetSecurityToken(foo);
8193 // Create a function in env2 and add a reference to it in env1.
8194 Local<v8::Object> global2 = env2->Global();
8195 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8196 CompileRun("function getProp() {return prop;}");
8198 env1->Global()->Set(v8_str("getProp"),
8199 global2->Get(v8_str("getProp")));
8201 // Detach env2's global, and reuse the global object of env2
8203 env2->DetachGlobal();
8205 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8207 v8::Handle<v8::ObjectTemplate>(),
8209 env3->SetSecurityToken(v8_str("bar"));
8212 Local<v8::Object> global3 = env3->Global();
8213 CHECK(global2->Equals(global3));
8214 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8215 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8216 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8217 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8220 // Call getProp in env1, and it should return the value 1
8222 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8223 CHECK(get_prop->IsFunction());
8224 v8::TryCatch try_catch(env1->GetIsolate());
8225 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8226 CHECK(!try_catch.HasCaught());
8227 CHECK_EQ(1, r->Int32Value());
8230 // Check that env3 is not accessible from env1
8232 Local<Value> r = global3->Get(v8_str("prop2"));
8238 TEST(DetachGlobal) {
8240 v8::HandleScope scope(env1->GetIsolate());
8242 // Create second environment.
8243 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8245 Local<Value> foo = v8_str("foo");
8247 // Set same security token for env1 and env2.
8248 env1->SetSecurityToken(foo);
8249 env2->SetSecurityToken(foo);
8251 // Create a property on the global object in env2.
8253 v8::Context::Scope scope(env2);
8254 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8257 // Create a reference to env2 global from env1 global.
8258 env1->Global()->Set(v8_str("other"), env2->Global());
8260 // Check that we have access to other.p in env2 from env1.
8261 Local<Value> result = CompileRun("other.p");
8262 CHECK(result->IsInt32());
8263 CHECK_EQ(42, result->Int32Value());
8265 // Hold on to global from env2 and detach global from env2.
8266 Local<v8::Object> global2 = env2->Global();
8267 env2->DetachGlobal();
8269 // Check that the global has been detached. No other.p property can
8271 result = CompileRun("other.p");
8272 CHECK(result.IsEmpty());
8274 // Reuse global2 for env3.
8275 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8277 v8::Handle<v8::ObjectTemplate>(),
8279 CHECK(global2->Equals(env3->Global()));
8281 // Start by using the same security token for env3 as for env1 and env2.
8282 env3->SetSecurityToken(foo);
8284 // Create a property on the global object in env3.
8286 v8::Context::Scope scope(env3);
8287 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8290 // Check that other.p is now the property in env3 and that we have access.
8291 result = CompileRun("other.p");
8292 CHECK(result->IsInt32());
8293 CHECK_EQ(24, result->Int32Value());
8295 // Change security token for env3 to something different from env1 and env2.
8296 env3->SetSecurityToken(v8_str("bar"));
8298 // Check that we do not have access to other.p in env1. |other| is now
8299 // the global object for env3 which has a different security token,
8300 // so access should be blocked.
8301 result = CompileRun("other.p");
8302 CHECK(result.IsEmpty());
8306 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8307 info.GetReturnValue().Set(
8308 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8312 TEST(DetachedAccesses) {
8314 v8::HandleScope scope(env1->GetIsolate());
8316 // Create second environment.
8317 Local<ObjectTemplate> inner_global_template =
8318 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8319 inner_global_template ->SetAccessorProperty(
8320 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8321 v8::Local<Context> env2 =
8322 Context::New(env1->GetIsolate(), NULL, inner_global_template);
8324 Local<Value> foo = v8_str("foo");
8326 // Set same security token for env1 and env2.
8327 env1->SetSecurityToken(foo);
8328 env2->SetSecurityToken(foo);
8330 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8333 v8::Context::Scope scope(env2);
8334 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8336 "function bound_x() { return x; }"
8337 "function get_x() { return this.x; }"
8338 "function get_x_w() { return (function() {return this.x;})(); }");
8339 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8340 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8341 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8342 env1->Global()->Set(
8344 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8347 Local<Object> env2_global = env2->Global();
8348 env2->DetachGlobal();
8350 Local<Value> result;
8351 result = CompileRun("bound_x()");
8352 CHECK(v8_str("env2_x")->Equals(result));
8353 result = CompileRun("get_x()");
8354 CHECK(result.IsEmpty());
8355 result = CompileRun("get_x_w()");
8356 CHECK(result.IsEmpty());
8357 result = CompileRun("this_x()");
8358 CHECK(v8_str("env2_x")->Equals(result));
8360 // Reattach env2's proxy
8361 env2 = Context::New(env1->GetIsolate(),
8363 v8::Handle<v8::ObjectTemplate>(),
8365 env2->SetSecurityToken(foo);
8367 v8::Context::Scope scope(env2);
8368 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8369 env2->Global()->Set(v8_str("env1"), env1->Global());
8370 result = CompileRun(
8372 "for (var i = 0; i < 4; i++ ) {"
8373 " results.push(env1.bound_x());"
8374 " results.push(env1.get_x());"
8375 " results.push(env1.get_x_w());"
8376 " results.push(env1.this_x());"
8379 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8380 CHECK_EQ(16u, results->Length());
8381 for (int i = 0; i < 16; i += 4) {
8382 CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8383 CHECK(v8_str("env1_x")->Equals(results->Get(i + 1)));
8384 CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8385 CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8389 result = CompileRun(
8391 "for (var i = 0; i < 4; i++ ) {"
8392 " results.push(bound_x());"
8393 " results.push(get_x());"
8394 " results.push(get_x_w());"
8395 " results.push(this_x());"
8398 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8399 CHECK_EQ(16u, results->Length());
8400 for (int i = 0; i < 16; i += 4) {
8401 CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8402 CHECK(v8_str("env3_x")->Equals(results->Get(i + 1)));
8403 CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8404 CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8407 result = CompileRun(
8409 "for (var i = 0; i < 4; i++ ) {"
8410 " results.push(this.bound_x());"
8411 " results.push(this.get_x());"
8412 " results.push(this.get_x_w());"
8413 " results.push(this.this_x());"
8416 results = Local<v8::Array>::Cast(result);
8417 CHECK_EQ(16u, results->Length());
8418 for (int i = 0; i < 16; i += 4) {
8419 CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8420 CHECK(v8_str("env1_x")->Equals(results->Get(i + 1)));
8421 CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8422 CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8427 static bool allowed_access = false;
8428 static bool AccessBlocker(Local<v8::Object> global, Local<Value> name,
8429 v8::AccessType type, Local<Value> data) {
8430 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8435 static int g_echo_value = -1;
8438 static void EchoGetter(
8440 const v8::PropertyCallbackInfo<v8::Value>& info) {
8441 info.GetReturnValue().Set(v8_num(g_echo_value));
8445 static void EchoSetter(Local<String> name,
8447 const v8::PropertyCallbackInfo<void>&) {
8448 if (value->IsNumber())
8449 g_echo_value = value->Int32Value();
8453 static void UnreachableGetter(
8455 const v8::PropertyCallbackInfo<v8::Value>& info) {
8456 CHECK(false); // This function should not be called..
8460 static void UnreachableSetter(Local<String>,
8462 const v8::PropertyCallbackInfo<void>&) {
8463 CHECK(false); // This function should nto be called.
8467 static void UnreachableFunction(
8468 const v8::FunctionCallbackInfo<v8::Value>& info) {
8469 CHECK(false); // This function should not be called..
8473 TEST(AccessControl) {
8474 v8::Isolate* isolate = CcTest::isolate();
8475 v8::HandleScope handle_scope(isolate);
8476 v8::Handle<v8::ObjectTemplate> global_template =
8477 v8::ObjectTemplate::New(isolate);
8479 global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
8481 // Add an accessor accessible by cross-domain JS code.
8482 global_template->SetAccessor(
8483 v8_str("accessible_prop"),
8484 EchoGetter, EchoSetter,
8485 v8::Handle<Value>(),
8486 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8489 // Add an accessor that is not accessible by cross-domain JS code.
8490 global_template->SetAccessor(v8_str("blocked_prop"),
8491 UnreachableGetter, UnreachableSetter,
8492 v8::Handle<Value>(),
8495 global_template->SetAccessorProperty(
8496 v8_str("blocked_js_prop"),
8497 v8::FunctionTemplate::New(isolate, UnreachableFunction),
8498 v8::FunctionTemplate::New(isolate, UnreachableFunction),
8502 // Create an environment
8503 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8506 v8::Handle<v8::Object> global0 = context0->Global();
8508 // Define a property with JS getter and setter.
8510 "function getter() { return 'getter'; };\n"
8511 "function setter() { return 'setter'; }\n"
8512 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8514 Local<Value> getter = global0->Get(v8_str("getter"));
8515 Local<Value> setter = global0->Get(v8_str("setter"));
8517 // And define normal element.
8518 global0->Set(239, v8_str("239"));
8520 // Define an element with JS getter and setter.
8522 "function el_getter() { return 'el_getter'; };\n"
8523 "function el_setter() { return 'el_setter'; };\n"
8524 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8526 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8527 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8529 v8::HandleScope scope1(isolate);
8531 v8::Local<Context> context1 = Context::New(isolate);
8534 v8::Handle<v8::Object> global1 = context1->Global();
8535 global1->Set(v8_str("other"), global0);
8537 // Access blocked property.
8538 CompileRun("other.blocked_prop = 1");
8540 CHECK(CompileRun("other.blocked_prop").IsEmpty());
8541 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
8544 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
8546 // Access blocked element.
8547 CHECK(CompileRun("other[239] = 1").IsEmpty());
8549 CHECK(CompileRun("other[239]").IsEmpty());
8550 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
8551 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
8553 allowed_access = true;
8554 // Now we can enumerate the property.
8555 ExpectTrue("propertyIsEnumerable.call(other, '239')");
8556 allowed_access = false;
8558 // Access a property with JS accessor.
8559 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
8561 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
8562 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
8565 allowed_access = true;
8567 ExpectString("other.js_accessor_p", "getter");
8569 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8571 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8573 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8575 allowed_access = false;
8577 // Access an element with JS accessor.
8578 CHECK(CompileRun("other[42] = 2").IsEmpty());
8580 CHECK(CompileRun("other[42]").IsEmpty());
8581 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
8583 allowed_access = true;
8585 ExpectString("other[42]", "el_getter");
8586 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8587 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8588 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8590 allowed_access = false;
8592 v8::Handle<Value> value;
8594 // Access accessible property
8595 value = CompileRun("other.accessible_prop = 3");
8596 CHECK(value->IsNumber());
8597 CHECK_EQ(3, value->Int32Value());
8598 CHECK_EQ(3, g_echo_value);
8600 value = CompileRun("other.accessible_prop");
8601 CHECK(value->IsNumber());
8602 CHECK_EQ(3, value->Int32Value());
8605 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
8606 CHECK(value->IsNumber());
8607 CHECK_EQ(3, value->Int32Value());
8609 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
8610 CHECK(value->IsTrue());
8612 // Enumeration doesn't enumerate accessors from inaccessible objects in
8613 // the prototype chain even if the accessors are in themselves accessible.
8616 " var obj = { '__proto__': other };"
8618 " for (var p in obj) {"
8619 " if (p == 'accessible_prop' ||"
8620 " p == 'blocked_js_prop' ||"
8621 " p == 'blocked_js_prop') {"
8630 CHECK(value->IsTrue());
8637 TEST(AccessControlES5) {
8638 v8::Isolate* isolate = CcTest::isolate();
8639 v8::HandleScope handle_scope(isolate);
8640 v8::Handle<v8::ObjectTemplate> global_template =
8641 v8::ObjectTemplate::New(isolate);
8643 global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
8645 // Add accessible accessor.
8646 global_template->SetAccessor(
8647 v8_str("accessible_prop"),
8648 EchoGetter, EchoSetter,
8649 v8::Handle<Value>(),
8650 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8653 // Add an accessor that is not accessible by cross-domain JS code.
8654 global_template->SetAccessor(v8_str("blocked_prop"),
8655 UnreachableGetter, UnreachableSetter,
8656 v8::Handle<Value>(),
8659 // Create an environment
8660 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8663 v8::Handle<v8::Object> global0 = context0->Global();
8665 v8::Local<Context> context1 = Context::New(isolate);
8667 v8::Handle<v8::Object> global1 = context1->Global();
8668 global1->Set(v8_str("other"), global0);
8670 // Regression test for issue 1154.
8671 CHECK(CompileRun("Object.keys(other)").IsEmpty());
8672 CHECK(CompileRun("other.blocked_prop").IsEmpty());
8674 // Regression test for issue 1027.
8675 CompileRun("Object.defineProperty(\n"
8676 " other, 'blocked_prop', {configurable: false})");
8677 CHECK(CompileRun("other.blocked_prop").IsEmpty());
8678 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
8681 // Regression test for issue 1171.
8682 ExpectTrue("Object.isExtensible(other)");
8683 CompileRun("Object.preventExtensions(other)");
8684 ExpectTrue("Object.isExtensible(other)");
8686 // Object.seal and Object.freeze.
8687 CompileRun("Object.freeze(other)");
8688 ExpectTrue("Object.isExtensible(other)");
8690 CompileRun("Object.seal(other)");
8691 ExpectTrue("Object.isExtensible(other)");
8693 // Regression test for issue 1250.
8694 // Make sure that we can set the accessible accessors value using normal
8696 CompileRun("other.accessible_prop = 42");
8697 CHECK_EQ(42, g_echo_value);
8699 v8::Handle<Value> value;
8700 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
8701 value = CompileRun("other.accessible_prop == 42");
8702 CHECK(value->IsTrue());
8706 static bool AccessAlwaysBlocked(Local<v8::Object> global, Local<Value> name,
8707 v8::AccessType type, Local<Value> data) {
8708 i::PrintF("Access blocked.\n");
8713 THREADED_TEST(AccessControlGetOwnPropertyNames) {
8714 v8::Isolate* isolate = CcTest::isolate();
8715 v8::HandleScope handle_scope(isolate);
8716 v8::Handle<v8::ObjectTemplate> obj_template =
8717 v8::ObjectTemplate::New(isolate);
8719 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
8720 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8722 // Create an environment
8723 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
8726 v8::Handle<v8::Object> global0 = context0->Global();
8728 v8::HandleScope scope1(CcTest::isolate());
8730 v8::Local<Context> context1 = Context::New(isolate);
8733 v8::Handle<v8::Object> global1 = context1->Global();
8734 global1->Set(v8_str("other"), global0);
8735 global1->Set(v8_str("object"), obj_template->NewInstance());
8737 v8::Handle<Value> value;
8739 // Attempt to get the property names of the other global object and
8740 // of an object that requires access checks. Accessing the other
8741 // global object should be blocked by access checks on the global
8742 // proxy object. Accessing the object that requires access checks
8743 // is blocked by the access checks on the object itself.
8744 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
8745 CHECK(value.IsEmpty());
8747 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
8748 CHECK(value.IsEmpty());
8755 TEST(SuperAccessControl) {
8756 i::FLAG_allow_natives_syntax = true;
8757 v8::Isolate* isolate = CcTest::isolate();
8758 v8::HandleScope handle_scope(isolate);
8759 v8::Handle<v8::ObjectTemplate> obj_template =
8760 v8::ObjectTemplate::New(isolate);
8761 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8763 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
8766 v8::TryCatch try_catch(isolate);
8768 "var f = { m() { return super.hasOwnProperty; } }.m;"
8769 "var m = %ToMethod(f, prohibited);"
8771 CHECK(try_catch.HasCaught());
8775 v8::TryCatch try_catch(isolate);
8777 "var f = {m() { return super[42]; } }.m;"
8778 "var m = %ToMethod(f, prohibited);"
8780 CHECK(try_catch.HasCaught());
8784 v8::TryCatch try_catch(isolate);
8786 "var f = {m() { super.hasOwnProperty = function () {}; } }.m;"
8787 "var m = %ToMethod(f, prohibited);"
8789 CHECK(try_catch.HasCaught());
8793 v8::TryCatch try_catch(isolate);
8795 "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
8799 " super.x = function () {};"
8802 "var m = %ToMethod(f, prohibited);"
8804 CHECK(try_catch.HasCaught());
8809 TEST(Regress470113) {
8810 v8::Isolate* isolate = CcTest::isolate();
8811 v8::HandleScope handle_scope(isolate);
8812 v8::Handle<v8::ObjectTemplate> obj_template =
8813 v8::ObjectTemplate::New(isolate);
8814 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8816 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
8819 v8::TryCatch try_catch(isolate);
8822 "class C extends Object {\n"
8823 " m() { super.powned = 'Powned!'; }\n"
8825 "let c = new C();\n"
8826 "c.m.call(prohibited)");
8828 CHECK(try_catch.HasCaught());
8833 static void ConstTenGetter(Local<String> name,
8834 const v8::PropertyCallbackInfo<v8::Value>& info) {
8835 info.GetReturnValue().Set(v8_num(10));
8839 THREADED_TEST(CrossDomainAccessors) {
8840 v8::Isolate* isolate = CcTest::isolate();
8841 v8::HandleScope handle_scope(isolate);
8843 v8::Handle<v8::FunctionTemplate> func_template =
8844 v8::FunctionTemplate::New(isolate);
8846 v8::Handle<v8::ObjectTemplate> global_template =
8847 func_template->InstanceTemplate();
8849 v8::Handle<v8::ObjectTemplate> proto_template =
8850 func_template->PrototypeTemplate();
8852 // Add an accessor to proto that's accessible by cross-domain JS code.
8853 proto_template->SetAccessor(v8_str("accessible"),
8855 v8::Handle<Value>(),
8858 // Add an accessor that is not accessible by cross-domain JS code.
8859 global_template->SetAccessor(v8_str("unreachable"),
8860 UnreachableGetter, 0,
8861 v8::Handle<Value>(),
8864 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8867 Local<v8::Object> global = context0->Global();
8868 // Add a normal property that shadows 'accessible'
8869 global->Set(v8_str("accessible"), v8_num(11));
8871 // Enter a new context.
8872 v8::HandleScope scope1(CcTest::isolate());
8873 v8::Local<Context> context1 = Context::New(isolate);
8876 v8::Handle<v8::Object> global1 = context1->Global();
8877 global1->Set(v8_str("other"), global);
8879 // Should return 10, instead of 11
8880 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
8881 CHECK(value->IsNumber());
8882 CHECK_EQ(10, value->Int32Value());
8884 value = v8_compile("other.unreachable")->Run();
8885 CHECK(value.IsEmpty());
8892 static int access_count = 0;
8894 static bool AccessCounter(Local<v8::Object> global, Local<Value> name,
8895 v8::AccessType type, Local<Value> data) {
8901 // This one is too easily disturbed by other tests.
8902 TEST(AccessControlIC) {
8905 v8::Isolate* isolate = CcTest::isolate();
8906 v8::HandleScope handle_scope(isolate);
8908 // Create an environment.
8909 v8::Local<Context> context0 = Context::New(isolate);
8912 // Create an object that requires access-check functions to be
8913 // called for cross-domain access.
8914 v8::Handle<v8::ObjectTemplate> object_template =
8915 v8::ObjectTemplate::New(isolate);
8916 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
8917 Local<v8::Object> object = object_template->NewInstance();
8919 v8::HandleScope scope1(isolate);
8921 // Create another environment.
8922 v8::Local<Context> context1 = Context::New(isolate);
8925 // Make easy access to the object from the other environment.
8926 v8::Handle<v8::Object> global1 = context1->Global();
8927 global1->Set(v8_str("obj"), object);
8929 v8::Handle<Value> value;
8931 // Check that the named access-control function is called every time.
8932 CompileRun("function testProp(obj) {"
8933 " for (var i = 0; i < 10; i++) obj.prop = 1;"
8934 " for (var j = 0; j < 10; j++) obj.prop;"
8937 value = CompileRun("testProp(obj)");
8938 CHECK(value->IsNumber());
8939 CHECK_EQ(1, value->Int32Value());
8940 CHECK_EQ(21, access_count);
8942 // Check that the named access-control function is called every time.
8943 CompileRun("var p = 'prop';"
8944 "function testKeyed(obj) {"
8945 " for (var i = 0; i < 10; i++) obj[p] = 1;"
8946 " for (var j = 0; j < 10; j++) obj[p];"
8949 // Use obj which requires access checks. No inline caching is used
8951 value = CompileRun("testKeyed(obj)");
8952 CHECK(value->IsNumber());
8953 CHECK_EQ(1, value->Int32Value());
8954 CHECK_EQ(42, access_count);
8955 // Force the inline caches into generic state and try again.
8956 CompileRun("testKeyed({ a: 0 })");
8957 CompileRun("testKeyed({ b: 0 })");
8958 value = CompileRun("testKeyed(obj)");
8959 CHECK(value->IsNumber());
8960 CHECK_EQ(1, value->Int32Value());
8961 CHECK_EQ(63, access_count);
8963 // Check that the indexed access-control function is called every time.
8966 CompileRun("function testIndexed(obj) {"
8967 " for (var i = 0; i < 10; i++) obj[0] = 1;"
8968 " for (var j = 0; j < 10; j++) obj[0];"
8971 value = CompileRun("testIndexed(obj)");
8972 CHECK(value->IsNumber());
8973 CHECK_EQ(1, value->Int32Value());
8974 CHECK_EQ(21, access_count);
8975 // Force the inline caches into generic state.
8976 CompileRun("testIndexed(new Array(1))");
8977 // Test that the indexed access check is called.
8978 value = CompileRun("testIndexed(obj)");
8979 CHECK(value->IsNumber());
8980 CHECK_EQ(1, value->Int32Value());
8981 CHECK_EQ(42, access_count);
8984 // Check that the named access check is called when invoking
8985 // functions on an object that requires access checks.
8986 CompileRun("obj.f = function() {}");
8987 CompileRun("function testCallNormal(obj) {"
8988 " for (var i = 0; i < 10; i++) obj.f();"
8990 CompileRun("testCallNormal(obj)");
8991 printf("%i\n", access_count);
8992 CHECK_EQ(11, access_count);
8994 // Force obj into slow case.
8995 value = CompileRun("delete obj.prop");
8996 CHECK(value->BooleanValue());
8997 // Force inline caches into dictionary probing mode.
8998 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
8999 // Test that the named access check is called.
9000 value = CompileRun("testProp(obj);");
9001 CHECK(value->IsNumber());
9002 CHECK_EQ(1, value->Int32Value());
9003 CHECK_EQ(33, access_count);
9005 // Force the call inline cache into dictionary probing mode.
9006 CompileRun("o.f = function() {}; testCallNormal(o)");
9007 // Test that the named access check is still called for each
9008 // invocation of the function.
9009 value = CompileRun("testCallNormal(obj)");
9010 CHECK_EQ(43, access_count);
9017 THREADED_TEST(Version) { v8::V8::GetVersion(); }
9020 static void InstanceFunctionCallback(
9021 const v8::FunctionCallbackInfo<v8::Value>& args) {
9022 ApiTestFuzzer::Fuzz();
9023 args.GetReturnValue().Set(v8_num(12));
9027 THREADED_TEST(InstanceProperties) {
9028 LocalContext context;
9029 v8::Isolate* isolate = context->GetIsolate();
9030 v8::HandleScope handle_scope(isolate);
9032 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9033 Local<ObjectTemplate> instance = t->InstanceTemplate();
9035 instance->Set(v8_str("x"), v8_num(42));
9036 instance->Set(v8_str("f"),
9037 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9039 Local<Value> o = t->GetFunction()->NewInstance();
9041 context->Global()->Set(v8_str("i"), o);
9042 Local<Value> value = CompileRun("i.x");
9043 CHECK_EQ(42, value->Int32Value());
9045 value = CompileRun("i.f()");
9046 CHECK_EQ(12, value->Int32Value());
9050 static void GlobalObjectInstancePropertiesGet(
9051 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
9052 ApiTestFuzzer::Fuzz();
9056 THREADED_TEST(GlobalObjectInstanceProperties) {
9057 v8::Isolate* isolate = CcTest::isolate();
9058 v8::HandleScope handle_scope(isolate);
9060 Local<Value> global_object;
9062 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9063 t->InstanceTemplate()->SetHandler(
9064 v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
9065 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9066 instance_template->Set(v8_str("x"), v8_num(42));
9067 instance_template->Set(v8_str("f"),
9068 v8::FunctionTemplate::New(isolate,
9069 InstanceFunctionCallback));
9071 // The script to check how Crankshaft compiles missing global function
9072 // invocations. function g is not defined and should throw on call.
9073 const char* script =
9074 "function wrapper(call) {"
9075 " var x = 0, y = 1;"
9076 " for (var i = 0; i < 1000; i++) {"
9082 "for (var i = 0; i < 17; i++) wrapper(false);"
9084 "try { wrapper(true); } catch (e) { thrown = 1; };"
9088 LocalContext env(NULL, instance_template);
9089 // Hold on to the global object so it can be used again in another
9090 // environment initialization.
9091 global_object = env->Global();
9093 Local<Value> value = CompileRun("x");
9094 CHECK_EQ(42, value->Int32Value());
9095 value = CompileRun("f()");
9096 CHECK_EQ(12, value->Int32Value());
9097 value = CompileRun(script);
9098 CHECK_EQ(1, value->Int32Value());
9102 // Create new environment reusing the global object.
9103 LocalContext env(NULL, instance_template, global_object);
9104 Local<Value> value = CompileRun("x");
9105 CHECK_EQ(42, value->Int32Value());
9106 value = CompileRun("f()");
9107 CHECK_EQ(12, value->Int32Value());
9108 value = CompileRun(script);
9109 CHECK_EQ(1, value->Int32Value());
9114 THREADED_TEST(CallKnownGlobalReceiver) {
9115 v8::Isolate* isolate = CcTest::isolate();
9116 v8::HandleScope handle_scope(isolate);
9118 Local<Value> global_object;
9120 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9121 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9123 // The script to check that we leave global object not
9124 // global object proxy on stack when we deoptimize from inside
9125 // arguments evaluation.
9126 // To provoke error we need to both force deoptimization
9127 // from arguments evaluation and to force CallIC to take
9128 // CallIC_Miss code path that can't cope with global proxy.
9129 const char* script =
9130 "function bar(x, y) { try { } finally { } }"
9131 "function baz(x) { try { } finally { } }"
9132 "function bom(x) { try { } finally { } }"
9133 "function foo(x) { bar([x], bom(2)); }"
9134 "for (var i = 0; i < 10000; i++) foo(1);"
9139 LocalContext env(NULL, instance_template);
9140 // Hold on to the global object so it can be used again in another
9141 // environment initialization.
9142 global_object = env->Global();
9143 foo = CompileRun(script);
9147 // Create new environment reusing the global object.
9148 LocalContext env(NULL, instance_template, global_object);
9149 env->Global()->Set(v8_str("foo"), foo);
9150 CompileRun("foo()");
9155 static void ShadowFunctionCallback(
9156 const v8::FunctionCallbackInfo<v8::Value>& args) {
9157 ApiTestFuzzer::Fuzz();
9158 args.GetReturnValue().Set(v8_num(42));
9162 static int shadow_y;
9163 static int shadow_y_setter_call_count;
9164 static int shadow_y_getter_call_count;
9167 static void ShadowYSetter(Local<String>,
9169 const v8::PropertyCallbackInfo<void>&) {
9170 shadow_y_setter_call_count++;
9175 static void ShadowYGetter(Local<String> name,
9176 const v8::PropertyCallbackInfo<v8::Value>& info) {
9177 ApiTestFuzzer::Fuzz();
9178 shadow_y_getter_call_count++;
9179 info.GetReturnValue().Set(v8_num(shadow_y));
9183 static void ShadowIndexedGet(uint32_t index,
9184 const v8::PropertyCallbackInfo<v8::Value>&) {
9188 static void ShadowNamedGet(Local<Name> key,
9189 const v8::PropertyCallbackInfo<v8::Value>&) {}
9192 THREADED_TEST(ShadowObject) {
9193 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9194 v8::Isolate* isolate = CcTest::isolate();
9195 v8::HandleScope handle_scope(isolate);
9197 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
9198 LocalContext context(NULL, global_template);
9200 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9201 t->InstanceTemplate()->SetHandler(
9202 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
9203 t->InstanceTemplate()->SetHandler(
9204 v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
9205 Local<ObjectTemplate> proto = t->PrototypeTemplate();
9206 Local<ObjectTemplate> instance = t->InstanceTemplate();
9208 proto->Set(v8_str("f"),
9209 v8::FunctionTemplate::New(isolate,
9210 ShadowFunctionCallback,
9212 proto->Set(v8_str("x"), v8_num(12));
9214 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9216 Local<Value> o = t->GetFunction()->NewInstance();
9217 context->Global()->Set(v8_str("__proto__"), o);
9219 Local<Value> value =
9220 CompileRun("this.propertyIsEnumerable(0)");
9221 CHECK(value->IsBoolean());
9222 CHECK(!value->BooleanValue());
9224 value = CompileRun("x");
9225 CHECK_EQ(12, value->Int32Value());
9227 value = CompileRun("f()");
9228 CHECK_EQ(42, value->Int32Value());
9230 CompileRun("y = 43");
9231 CHECK_EQ(1, shadow_y_setter_call_count);
9232 value = CompileRun("y");
9233 CHECK_EQ(1, shadow_y_getter_call_count);
9234 CHECK_EQ(42, value->Int32Value());
9238 THREADED_TEST(HiddenPrototype) {
9239 LocalContext context;
9240 v8::Isolate* isolate = context->GetIsolate();
9241 v8::HandleScope handle_scope(isolate);
9243 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9244 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9245 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9246 t1->SetHiddenPrototype(true);
9247 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9248 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9249 t2->SetHiddenPrototype(true);
9250 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9251 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9252 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9254 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9255 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9256 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9257 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9259 // Setting the prototype on an object skips hidden prototypes.
9260 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9261 o0->Set(v8_str("__proto__"), o1);
9262 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9263 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9264 o0->Set(v8_str("__proto__"), o2);
9265 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9266 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9267 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9268 o0->Set(v8_str("__proto__"), o3);
9269 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9270 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9271 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9272 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9274 // Getting the prototype of o0 should get the first visible one
9275 // which is o3. Therefore, z should not be defined on the prototype
9277 Local<Value> proto = o0->Get(v8_str("__proto__"));
9278 CHECK(proto->IsObject());
9279 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
9283 THREADED_TEST(HiddenPrototypeSet) {
9284 LocalContext context;
9285 v8::Isolate* isolate = context->GetIsolate();
9286 v8::HandleScope handle_scope(isolate);
9288 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
9289 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
9290 ht->SetHiddenPrototype(true);
9291 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
9292 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9294 Local<v8::Object> o = ot->GetFunction()->NewInstance();
9295 Local<v8::Object> h = ht->GetFunction()->NewInstance();
9296 Local<v8::Object> p = pt->GetFunction()->NewInstance();
9297 o->Set(v8_str("__proto__"), h);
9298 h->Set(v8_str("__proto__"), p);
9300 // Setting a property that exists on the hidden prototype goes there.
9301 o->Set(v8_str("x"), v8_num(7));
9302 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
9303 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
9304 CHECK(p->Get(v8_str("x"))->IsUndefined());
9306 // Setting a new property should not be forwarded to the hidden prototype.
9307 o->Set(v8_str("y"), v8_num(6));
9308 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
9309 CHECK(h->Get(v8_str("y"))->IsUndefined());
9310 CHECK(p->Get(v8_str("y"))->IsUndefined());
9312 // Setting a property that only exists on a prototype of the hidden prototype
9313 // is treated normally again.
9314 p->Set(v8_str("z"), v8_num(8));
9315 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
9316 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9317 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9318 o->Set(v8_str("z"), v8_num(9));
9319 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
9320 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9321 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9325 // Regression test for issue 2457.
9326 THREADED_TEST(HiddenPrototypeIdentityHash) {
9327 LocalContext context;
9328 v8::HandleScope handle_scope(context->GetIsolate());
9330 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
9331 t->SetHiddenPrototype(true);
9332 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
9333 Handle<Object> p = t->GetFunction()->NewInstance();
9334 Handle<Object> o = Object::New(context->GetIsolate());
9337 int hash = o->GetIdentityHash();
9339 o->Set(v8_str("foo"), v8_num(42));
9340 DCHECK_EQ(hash, o->GetIdentityHash());
9344 THREADED_TEST(SetPrototype) {
9345 LocalContext context;
9346 v8::Isolate* isolate = context->GetIsolate();
9347 v8::HandleScope handle_scope(isolate);
9349 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9350 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9351 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9352 t1->SetHiddenPrototype(true);
9353 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9354 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9355 t2->SetHiddenPrototype(true);
9356 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9357 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9358 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9360 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9361 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9362 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9363 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9365 // Setting the prototype on an object does not skip hidden prototypes.
9366 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9367 CHECK(o0->SetPrototype(o1));
9368 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9369 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9370 CHECK(o1->SetPrototype(o2));
9371 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9372 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9373 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9374 CHECK(o2->SetPrototype(o3));
9375 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9376 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9377 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9378 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9380 // Getting the prototype of o0 should get the first visible one
9381 // which is o3. Therefore, z should not be defined on the prototype
9383 Local<Value> proto = o0->Get(v8_str("__proto__"));
9384 CHECK(proto->IsObject());
9385 CHECK(proto.As<v8::Object>()->Equals(o3));
9387 // However, Object::GetPrototype ignores hidden prototype.
9388 Local<Value> proto0 = o0->GetPrototype();
9389 CHECK(proto0->IsObject());
9390 CHECK(proto0.As<v8::Object>()->Equals(o1));
9392 Local<Value> proto1 = o1->GetPrototype();
9393 CHECK(proto1->IsObject());
9394 CHECK(proto1.As<v8::Object>()->Equals(o2));
9396 Local<Value> proto2 = o2->GetPrototype();
9397 CHECK(proto2->IsObject());
9398 CHECK(proto2.As<v8::Object>()->Equals(o3));
9402 // Getting property names of an object with a prototype chain that
9403 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
9404 // crash the runtime.
9405 THREADED_TEST(Regress91517) {
9406 i::FLAG_allow_natives_syntax = true;
9407 LocalContext context;
9408 v8::Isolate* isolate = context->GetIsolate();
9409 v8::HandleScope handle_scope(isolate);
9411 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9412 t1->SetHiddenPrototype(true);
9413 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
9414 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9415 t2->SetHiddenPrototype(true);
9416 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
9417 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
9418 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
9419 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9420 t3->SetHiddenPrototype(true);
9421 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
9422 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
9423 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
9425 // Force dictionary-based properties.
9426 i::ScopedVector<char> name_buf(1024);
9427 for (int i = 1; i <= 1000; i++) {
9428 i::SNPrintF(name_buf, "sdf%d", i);
9429 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
9432 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9433 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9434 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9435 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
9437 // Create prototype chain of hidden prototypes.
9438 CHECK(o4->SetPrototype(o3));
9439 CHECK(o3->SetPrototype(o2));
9440 CHECK(o2->SetPrototype(o1));
9442 // Call the runtime version of GetOwnPropertyNames() on the natively
9443 // created object through JavaScript.
9444 context->Global()->Set(v8_str("obj"), o4);
9445 // PROPERTY_ATTRIBUTES_NONE = 0
9446 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
9448 ExpectInt32("names.length", 1006);
9449 ExpectTrue("names.indexOf(\"baz\") >= 0");
9450 ExpectTrue("names.indexOf(\"boo\") >= 0");
9451 ExpectTrue("names.indexOf(\"foo\") >= 0");
9452 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
9453 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
9454 ExpectFalse("names[1005] == undefined");
9458 // Getting property names of an object with a hidden and inherited
9459 // prototype should not duplicate the accessor properties inherited.
9460 THREADED_TEST(Regress269562) {
9461 i::FLAG_allow_natives_syntax = true;
9462 LocalContext context;
9463 v8::HandleScope handle_scope(context->GetIsolate());
9465 Local<v8::FunctionTemplate> t1 =
9466 v8::FunctionTemplate::New(context->GetIsolate());
9467 t1->SetHiddenPrototype(true);
9469 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
9470 i1->SetAccessor(v8_str("foo"),
9471 SimpleAccessorGetter, SimpleAccessorSetter);
9472 i1->SetAccessor(v8_str("bar"),
9473 SimpleAccessorGetter, SimpleAccessorSetter);
9474 i1->SetAccessor(v8_str("baz"),
9475 SimpleAccessorGetter, SimpleAccessorSetter);
9476 i1->Set(v8_str("n1"), v8_num(1));
9477 i1->Set(v8_str("n2"), v8_num(2));
9479 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9480 Local<v8::FunctionTemplate> t2 =
9481 v8::FunctionTemplate::New(context->GetIsolate());
9482 t2->SetHiddenPrototype(true);
9484 // Inherit from t1 and mark prototype as hidden.
9486 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
9488 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9489 CHECK(o2->SetPrototype(o1));
9491 v8::Local<v8::Symbol> sym =
9492 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
9493 o1->Set(sym, v8_num(3));
9495 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
9497 // Call the runtime version of GetOwnPropertyNames() on
9498 // the natively created object through JavaScript.
9499 context->Global()->Set(v8_str("obj"), o2);
9500 context->Global()->Set(v8_str("sym"), sym);
9501 // PROPERTY_ATTRIBUTES_NONE = 0
9502 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
9504 ExpectInt32("names.length", 7);
9505 ExpectTrue("names.indexOf(\"foo\") >= 0");
9506 ExpectTrue("names.indexOf(\"bar\") >= 0");
9507 ExpectTrue("names.indexOf(\"baz\") >= 0");
9508 ExpectTrue("names.indexOf(\"n1\") >= 0");
9509 ExpectTrue("names.indexOf(\"n2\") >= 0");
9510 ExpectTrue("names.indexOf(sym) >= 0");
9511 ExpectTrue("names.indexOf(\"mine\") >= 0");
9515 THREADED_TEST(FunctionReadOnlyPrototype) {
9516 LocalContext context;
9517 v8::Isolate* isolate = context->GetIsolate();
9518 v8::HandleScope handle_scope(isolate);
9520 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9521 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9522 t1->ReadOnlyPrototype();
9523 context->Global()->Set(v8_str("func1"), t1->GetFunction());
9524 // Configured value of ReadOnly flag.
9527 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
9528 " return (descriptor['writable'] == false);"
9529 "})()")->BooleanValue());
9530 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
9532 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
9534 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9535 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9536 context->Global()->Set(v8_str("func2"), t2->GetFunction());
9537 // Default value of ReadOnly flag.
9540 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
9541 " return (descriptor['writable'] == true);"
9542 "})()")->BooleanValue());
9543 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
9547 THREADED_TEST(SetPrototypeThrows) {
9548 LocalContext context;
9549 v8::Isolate* isolate = context->GetIsolate();
9550 v8::HandleScope handle_scope(isolate);
9552 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9554 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
9555 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
9557 CHECK(o0->SetPrototype(o1));
9558 // If setting the prototype leads to the cycle, SetPrototype should
9559 // return false and keep VM in sane state.
9560 v8::TryCatch try_catch(isolate);
9561 CHECK(!o1->SetPrototype(o0));
9562 CHECK(!try_catch.HasCaught());
9563 DCHECK(!CcTest::i_isolate()->has_pending_exception());
9565 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
9569 THREADED_TEST(FunctionRemovePrototype) {
9570 LocalContext context;
9571 v8::Isolate* isolate = context->GetIsolate();
9572 v8::HandleScope handle_scope(isolate);
9574 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9575 t1->RemovePrototype();
9576 Local<v8::Function> fun = t1->GetFunction();
9577 context->Global()->Set(v8_str("fun"), fun);
9578 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
9580 v8::TryCatch try_catch(isolate);
9581 CompileRun("new fun()");
9582 CHECK(try_catch.HasCaught());
9586 CHECK(try_catch.HasCaught());
9590 THREADED_TEST(GetterSetterExceptions) {
9591 LocalContext context;
9592 v8::Isolate* isolate = context->GetIsolate();
9593 v8::HandleScope handle_scope(isolate);
9595 "function Foo() { };"
9596 "function Throw() { throw 5; };"
9598 "x.__defineSetter__('set', Throw);"
9599 "x.__defineGetter__('get', Throw);");
9600 Local<v8::Object> x =
9601 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
9602 v8::TryCatch try_catch(isolate);
9603 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9604 x->Get(v8_str("get"));
9605 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9606 x->Get(v8_str("get"));
9607 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9608 x->Get(v8_str("get"));
9609 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9610 x->Get(v8_str("get"));
9614 THREADED_TEST(Constructor) {
9615 LocalContext context;
9616 v8::Isolate* isolate = context->GetIsolate();
9617 v8::HandleScope handle_scope(isolate);
9618 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
9619 templ->SetClassName(v8_str("Fun"));
9620 Local<Function> cons = templ->GetFunction();
9621 context->Global()->Set(v8_str("Fun"), cons);
9622 Local<v8::Object> inst = cons->NewInstance();
9623 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
9624 CHECK(obj->IsJSObject());
9625 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
9626 CHECK(value->BooleanValue());
9630 static void ConstructorCallback(
9631 const v8::FunctionCallbackInfo<v8::Value>& args) {
9632 ApiTestFuzzer::Fuzz();
9635 if (args.IsConstructCall()) {
9636 Local<Object> Holder = args.Holder();
9637 This = Object::New(args.GetIsolate());
9638 Local<Value> proto = Holder->GetPrototype();
9639 if (proto->IsObject()) {
9640 This->SetPrototype(proto);
9646 This->Set(v8_str("a"), args[0]);
9647 args.GetReturnValue().Set(This);
9651 static void FakeConstructorCallback(
9652 const v8::FunctionCallbackInfo<v8::Value>& args) {
9653 ApiTestFuzzer::Fuzz();
9654 args.GetReturnValue().Set(args[0]);
9658 THREADED_TEST(ConstructorForObject) {
9659 LocalContext context;
9660 v8::Isolate* isolate = context->GetIsolate();
9661 v8::HandleScope handle_scope(isolate);
9664 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9665 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
9666 Local<Object> instance = instance_template->NewInstance();
9667 context->Global()->Set(v8_str("obj"), instance);
9668 v8::TryCatch try_catch(isolate);
9670 CHECK(!try_catch.HasCaught());
9672 // Call the Object's constructor with a 32-bit signed integer.
9673 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
9674 CHECK(!try_catch.HasCaught());
9675 CHECK(value->IsInt32());
9676 CHECK_EQ(28, value->Int32Value());
9678 Local<Value> args1[] = {v8_num(28)};
9679 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
9680 CHECK(value_obj1->IsObject());
9681 Local<Object> object1 = Local<Object>::Cast(value_obj1);
9682 value = object1->Get(v8_str("a"));
9683 CHECK(value->IsInt32());
9684 CHECK(!try_catch.HasCaught());
9685 CHECK_EQ(28, value->Int32Value());
9687 // Call the Object's constructor with a String.
9689 CompileRun("(function() { var o = new obj('tipli'); return o.a; })()");
9690 CHECK(!try_catch.HasCaught());
9691 CHECK(value->IsString());
9692 String::Utf8Value string_value1(value->ToString(isolate));
9693 CHECK_EQ(0, strcmp("tipli", *string_value1));
9695 Local<Value> args2[] = {v8_str("tipli")};
9696 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
9697 CHECK(value_obj2->IsObject());
9698 Local<Object> object2 = Local<Object>::Cast(value_obj2);
9699 value = object2->Get(v8_str("a"));
9700 CHECK(!try_catch.HasCaught());
9701 CHECK(value->IsString());
9702 String::Utf8Value string_value2(value->ToString(isolate));
9703 CHECK_EQ(0, strcmp("tipli", *string_value2));
9705 // Call the Object's constructor with a Boolean.
9706 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
9707 CHECK(!try_catch.HasCaught());
9708 CHECK(value->IsBoolean());
9709 CHECK_EQ(true, value->BooleanValue());
9711 Handle<Value> args3[] = {v8::True(isolate)};
9712 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
9713 CHECK(value_obj3->IsObject());
9714 Local<Object> object3 = Local<Object>::Cast(value_obj3);
9715 value = object3->Get(v8_str("a"));
9716 CHECK(!try_catch.HasCaught());
9717 CHECK(value->IsBoolean());
9718 CHECK_EQ(true, value->BooleanValue());
9720 // Call the Object's constructor with undefined.
9721 Handle<Value> args4[] = {v8::Undefined(isolate)};
9722 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
9723 CHECK(value_obj4->IsObject());
9724 Local<Object> object4 = Local<Object>::Cast(value_obj4);
9725 value = object4->Get(v8_str("a"));
9726 CHECK(!try_catch.HasCaught());
9727 CHECK(value->IsUndefined());
9729 // Call the Object's constructor with null.
9730 Handle<Value> args5[] = {v8::Null(isolate)};
9731 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
9732 CHECK(value_obj5->IsObject());
9733 Local<Object> object5 = Local<Object>::Cast(value_obj5);
9734 value = object5->Get(v8_str("a"));
9735 CHECK(!try_catch.HasCaught());
9736 CHECK(value->IsNull());
9739 // Check exception handling when there is no constructor set for the Object.
9741 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9742 Local<Object> instance = instance_template->NewInstance();
9743 context->Global()->Set(v8_str("obj2"), instance);
9744 v8::TryCatch try_catch(isolate);
9746 CHECK(!try_catch.HasCaught());
9748 value = CompileRun("new obj2(28)");
9749 CHECK(try_catch.HasCaught());
9750 String::Utf8Value exception_value1(try_catch.Exception());
9751 CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
9754 Local<Value> args[] = {v8_num(29)};
9755 value = instance->CallAsConstructor(1, args);
9756 CHECK(try_catch.HasCaught());
9757 String::Utf8Value exception_value2(try_catch.Exception());
9759 0, strcmp("TypeError: #<Object> is not a function", *exception_value2));
9763 // Check the case when constructor throws exception.
9765 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9766 instance_template->SetCallAsFunctionHandler(ThrowValue);
9767 Local<Object> instance = instance_template->NewInstance();
9768 context->Global()->Set(v8_str("obj3"), instance);
9769 v8::TryCatch try_catch(isolate);
9771 CHECK(!try_catch.HasCaught());
9773 value = CompileRun("new obj3(22)");
9774 CHECK(try_catch.HasCaught());
9775 String::Utf8Value exception_value1(try_catch.Exception());
9776 CHECK_EQ(0, strcmp("22", *exception_value1));
9779 Local<Value> args[] = {v8_num(23)};
9780 value = instance->CallAsConstructor(1, args);
9781 CHECK(try_catch.HasCaught());
9782 String::Utf8Value exception_value2(try_catch.Exception());
9783 CHECK_EQ(0, strcmp("23", *exception_value2));
9787 // Check whether constructor returns with an object or non-object.
9789 Local<FunctionTemplate> function_template =
9790 FunctionTemplate::New(isolate, FakeConstructorCallback);
9791 Local<Function> function = function_template->GetFunction();
9792 Local<Object> instance1 = function;
9793 context->Global()->Set(v8_str("obj4"), instance1);
9794 v8::TryCatch try_catch(isolate);
9796 CHECK(!try_catch.HasCaught());
9798 CHECK(instance1->IsObject());
9799 CHECK(instance1->IsFunction());
9801 value = CompileRun("new obj4(28)");
9802 CHECK(!try_catch.HasCaught());
9803 CHECK(value->IsObject());
9805 Local<Value> args1[] = {v8_num(28)};
9806 value = instance1->CallAsConstructor(1, args1);
9807 CHECK(!try_catch.HasCaught());
9808 CHECK(value->IsObject());
9810 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9811 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
9812 Local<Object> instance2 = instance_template->NewInstance();
9813 context->Global()->Set(v8_str("obj5"), instance2);
9814 CHECK(!try_catch.HasCaught());
9816 CHECK(instance2->IsObject());
9817 CHECK(!instance2->IsFunction());
9819 value = CompileRun("new obj5(28)");
9820 CHECK(!try_catch.HasCaught());
9821 CHECK(!value->IsObject());
9823 Local<Value> args2[] = {v8_num(28)};
9824 value = instance2->CallAsConstructor(1, args2);
9825 CHECK(!try_catch.HasCaught());
9826 CHECK(!value->IsObject());
9831 THREADED_TEST(FunctionDescriptorException) {
9832 LocalContext context;
9833 v8::Isolate* isolate = context->GetIsolate();
9834 v8::HandleScope handle_scope(isolate);
9835 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
9836 templ->SetClassName(v8_str("Fun"));
9837 Local<Function> cons = templ->GetFunction();
9838 context->Global()->Set(v8_str("Fun"), cons);
9839 Local<Value> value = CompileRun(
9842 " (new Fun()).blah()"
9844 " var str = String(e);"
9845 // " if (str.indexOf('TypeError') == -1) return 1;"
9846 // " if (str.indexOf('[object Fun]') != -1) return 2;"
9847 // " if (str.indexOf('#<Fun>') == -1) return 3;"
9853 CHECK_EQ(0, value->Int32Value());
9857 THREADED_TEST(EvalAliasedDynamic) {
9858 LocalContext current;
9859 v8::HandleScope scope(current->GetIsolate());
9861 // Tests where aliased eval can only be resolved dynamically.
9862 Local<Script> script = v8_compile(
9865 " with (x) { return eval('foo'); }"
9868 "result1 = f(new Object());"
9869 "result2 = f(this);"
9870 "var x = new Object();"
9871 "x.eval = function(x) { return 1; };"
9874 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
9875 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
9876 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
9878 v8::TryCatch try_catch(current->GetIsolate());
9879 script = v8_compile(
9882 " with (x) { return eval('bar'); }"
9884 "result4 = f(this)");
9886 CHECK(!try_catch.HasCaught());
9887 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
9893 THREADED_TEST(CrossEval) {
9894 v8::HandleScope scope(CcTest::isolate());
9896 LocalContext current;
9898 Local<String> token = v8_str("<security token>");
9899 other->SetSecurityToken(token);
9900 current->SetSecurityToken(token);
9902 // Set up reference from current to other.
9903 current->Global()->Set(v8_str("other"), other->Global());
9905 // Check that new variables are introduced in other context.
9906 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
9908 Local<Value> foo = other->Global()->Get(v8_str("foo"));
9909 CHECK_EQ(1234, foo->Int32Value());
9910 CHECK(!current->Global()->Has(v8_str("foo")));
9912 // Check that writing to non-existing properties introduces them in
9913 // the other context.
9914 script = v8_compile("other.eval('na = 1234')");
9916 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
9917 CHECK(!current->Global()->Has(v8_str("na")));
9919 // Check that global variables in current context are not visible in other
9921 v8::TryCatch try_catch(CcTest::isolate());
9922 script = v8_compile("var bar = 42; other.eval('bar');");
9923 Local<Value> result = script->Run();
9924 CHECK(try_catch.HasCaught());
9927 // Check that local variables in current context are not visible in other
9929 script = v8_compile(
9932 " return other.eval('baz');"
9934 result = script->Run();
9935 CHECK(try_catch.HasCaught());
9938 // Check that global variables in the other environment are visible
9939 // when evaluting code.
9940 other->Global()->Set(v8_str("bis"), v8_num(1234));
9941 script = v8_compile("other.eval('bis')");
9942 CHECK_EQ(1234, script->Run()->Int32Value());
9943 CHECK(!try_catch.HasCaught());
9945 // Check that the 'this' pointer points to the global object evaluating
9947 other->Global()->Set(v8_str("t"), other->Global());
9948 script = v8_compile("other.eval('this == t')");
9949 result = script->Run();
9950 CHECK(result->IsTrue());
9951 CHECK(!try_catch.HasCaught());
9953 // Check that variables introduced in with-statement are not visible in
9955 script = v8_compile("with({x:2}){other.eval('x')}");
9956 result = script->Run();
9957 CHECK(try_catch.HasCaught());
9960 // Check that you cannot use 'eval.call' with another object than the
9961 // current global object.
9962 script = v8_compile("other.y = 1; eval.call(other, 'y')");
9963 result = script->Run();
9964 CHECK(try_catch.HasCaught());
9968 // Test that calling eval in a context which has been detached from
9969 // its global proxy works.
9970 THREADED_TEST(EvalInDetachedGlobal) {
9971 v8::Isolate* isolate = CcTest::isolate();
9972 v8::HandleScope scope(isolate);
9974 v8::Local<Context> context0 = Context::New(isolate);
9975 v8::Local<Context> context1 = Context::New(isolate);
9977 // Set up function in context0 that uses eval from context0.
9979 v8::Handle<v8::Value> fun = CompileRun(
9983 " return function(s) { return e(s); }"
9987 // Put the function into context1 and call it before and after
9988 // detaching the global. Before detaching, the call succeeds and
9989 // after detaching and exception is thrown.
9991 context1->Global()->Set(v8_str("fun"), fun);
9992 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
9993 CHECK_EQ(42, x_value->Int32Value());
9994 context0->DetachGlobal();
9995 v8::TryCatch catcher(isolate);
9996 x_value = CompileRun("fun('x')");
9997 CHECK_EQ(42, x_value->Int32Value());
10002 THREADED_TEST(CrossLazyLoad) {
10003 v8::HandleScope scope(CcTest::isolate());
10004 LocalContext other;
10005 LocalContext current;
10007 Local<String> token = v8_str("<security token>");
10008 other->SetSecurityToken(token);
10009 current->SetSecurityToken(token);
10011 // Set up reference from current to other.
10012 current->Global()->Set(v8_str("other"), other->Global());
10014 // Trigger lazy loading in other context.
10015 Local<Script> script = v8_compile("other.eval('new Date(42)')");
10016 Local<Value> value = script->Run();
10017 CHECK_EQ(42.0, value->NumberValue());
10021 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10022 ApiTestFuzzer::Fuzz();
10023 if (args.IsConstructCall()) {
10024 if (args[0]->IsInt32()) {
10025 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10030 args.GetReturnValue().Set(args[0]);
10034 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10035 args.GetReturnValue().Set(args.This());
10039 // Test that a call handler can be set for objects which will allow
10040 // non-function objects created through the API to be called as
10042 THREADED_TEST(CallAsFunction) {
10043 LocalContext context;
10044 v8::Isolate* isolate = context->GetIsolate();
10045 v8::HandleScope scope(isolate);
10048 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10049 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10050 instance_template->SetCallAsFunctionHandler(call_as_function);
10051 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10052 context->Global()->Set(v8_str("obj"), instance);
10053 v8::TryCatch try_catch(isolate);
10054 Local<Value> value;
10055 CHECK(!try_catch.HasCaught());
10057 value = CompileRun("obj(42)");
10058 CHECK(!try_catch.HasCaught());
10059 CHECK_EQ(42, value->Int32Value());
10061 value = CompileRun("(function(o){return o(49)})(obj)");
10062 CHECK(!try_catch.HasCaught());
10063 CHECK_EQ(49, value->Int32Value());
10065 // test special case of call as function
10066 value = CompileRun("[obj]['0'](45)");
10067 CHECK(!try_catch.HasCaught());
10068 CHECK_EQ(45, value->Int32Value());
10070 value = CompileRun(
10071 "obj.call = Function.prototype.call;"
10072 "obj.call(null, 87)");
10073 CHECK(!try_catch.HasCaught());
10074 CHECK_EQ(87, value->Int32Value());
10076 // Regression tests for bug #1116356: Calling call through call/apply
10077 // must work for non-function receivers.
10078 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10079 value = CompileRun(apply_99);
10080 CHECK(!try_catch.HasCaught());
10081 CHECK_EQ(99, value->Int32Value());
10083 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10084 value = CompileRun(call_17);
10085 CHECK(!try_catch.HasCaught());
10086 CHECK_EQ(17, value->Int32Value());
10088 // Check that the call-as-function handler can be called through
10090 value = CompileRun("new obj(43)");
10091 CHECK(!try_catch.HasCaught());
10092 CHECK_EQ(-43, value->Int32Value());
10094 // Check that the call-as-function handler can be called through
10096 v8::Handle<Value> args[] = {v8_num(28)};
10097 value = instance->CallAsFunction(instance, 1, args);
10098 CHECK(!try_catch.HasCaught());
10099 CHECK_EQ(28, value->Int32Value());
10103 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10104 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10105 USE(instance_template);
10106 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10107 context->Global()->Set(v8_str("obj2"), instance);
10108 v8::TryCatch try_catch(isolate);
10109 Local<Value> value;
10110 CHECK(!try_catch.HasCaught());
10112 // Call an object without call-as-function handler through the JS
10113 value = CompileRun("obj2(28)");
10114 CHECK(value.IsEmpty());
10115 CHECK(try_catch.HasCaught());
10116 String::Utf8Value exception_value1(try_catch.Exception());
10117 // TODO(verwaest): Better message
10118 CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
10121 // Call an object without call-as-function handler through the API
10122 value = CompileRun("obj2(28)");
10123 v8::Handle<Value> args[] = {v8_num(28)};
10124 value = instance->CallAsFunction(instance, 1, args);
10125 CHECK(value.IsEmpty());
10126 CHECK(try_catch.HasCaught());
10127 String::Utf8Value exception_value2(try_catch.Exception());
10128 CHECK_EQ(0, strcmp("TypeError: [object Object] is not a function",
10129 *exception_value2));
10134 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10135 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10136 instance_template->SetCallAsFunctionHandler(ThrowValue);
10137 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10138 context->Global()->Set(v8_str("obj3"), instance);
10139 v8::TryCatch try_catch(isolate);
10140 Local<Value> value;
10141 CHECK(!try_catch.HasCaught());
10143 // Catch the exception which is thrown by call-as-function handler
10144 value = CompileRun("obj3(22)");
10145 CHECK(try_catch.HasCaught());
10146 String::Utf8Value exception_value1(try_catch.Exception());
10147 CHECK_EQ(0, strcmp("22", *exception_value1));
10150 v8::Handle<Value> args[] = {v8_num(23)};
10151 value = instance->CallAsFunction(instance, 1, args);
10152 CHECK(try_catch.HasCaught());
10153 String::Utf8Value exception_value2(try_catch.Exception());
10154 CHECK_EQ(0, strcmp("23", *exception_value2));
10159 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10160 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10161 instance_template->SetCallAsFunctionHandler(ReturnThis);
10162 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10164 Local<v8::Value> a1 =
10165 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10166 CHECK(a1->StrictEquals(instance));
10167 Local<v8::Value> a2 = instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10168 CHECK(a2->StrictEquals(instance));
10169 Local<v8::Value> a3 = instance->CallAsFunction(v8_num(42), 0, NULL);
10170 CHECK(a3->StrictEquals(instance));
10171 Local<v8::Value> a4 = instance->CallAsFunction(v8_str("hello"), 0, NULL);
10172 CHECK(a4->StrictEquals(instance));
10173 Local<v8::Value> a5 = instance->CallAsFunction(v8::True(isolate), 0, NULL);
10174 CHECK(a5->StrictEquals(instance));
10179 "function ReturnThisSloppy() {"
10182 "function ReturnThisStrict() {"
10186 Local<Function> ReturnThisSloppy = Local<Function>::Cast(
10187 context->Global()->Get(v8_str("ReturnThisSloppy")));
10188 Local<Function> ReturnThisStrict = Local<Function>::Cast(
10189 context->Global()->Get(v8_str("ReturnThisStrict")));
10191 Local<v8::Value> a1 =
10192 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10193 CHECK(a1->StrictEquals(context->Global()));
10194 Local<v8::Value> a2 =
10195 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10196 CHECK(a2->StrictEquals(context->Global()));
10197 Local<v8::Value> a3 = ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10198 CHECK(a3->IsNumberObject());
10199 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10200 Local<v8::Value> a4 =
10201 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10202 CHECK(a4->IsStringObject());
10203 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10204 Local<v8::Value> a5 =
10205 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10206 CHECK(a5->IsBooleanObject());
10207 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10209 Local<v8::Value> a6 =
10210 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10211 CHECK(a6->IsUndefined());
10212 Local<v8::Value> a7 =
10213 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10214 CHECK(a7->IsNull());
10215 Local<v8::Value> a8 = ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10216 CHECK(a8->StrictEquals(v8_num(42)));
10217 Local<v8::Value> a9 =
10218 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10219 CHECK(a9->StrictEquals(v8_str("hello")));
10220 Local<v8::Value> a10 =
10221 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10222 CHECK(a10->StrictEquals(v8::True(isolate)));
10227 // Check whether a non-function object is callable.
10228 THREADED_TEST(CallableObject) {
10229 LocalContext context;
10230 v8::Isolate* isolate = context->GetIsolate();
10231 v8::HandleScope scope(isolate);
10234 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10235 instance_template->SetCallAsFunctionHandler(call_as_function);
10236 Local<Object> instance = instance_template->NewInstance();
10237 v8::TryCatch try_catch(isolate);
10239 CHECK(instance->IsCallable());
10240 CHECK(!try_catch.HasCaught());
10244 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10245 Local<Object> instance = instance_template->NewInstance();
10246 v8::TryCatch try_catch(isolate);
10248 CHECK(!instance->IsCallable());
10249 CHECK(!try_catch.HasCaught());
10253 Local<FunctionTemplate> function_template =
10254 FunctionTemplate::New(isolate, call_as_function);
10255 Local<Function> function = function_template->GetFunction();
10256 Local<Object> instance = function;
10257 v8::TryCatch try_catch(isolate);
10259 CHECK(instance->IsCallable());
10260 CHECK(!try_catch.HasCaught());
10264 Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
10265 Local<Function> function = function_template->GetFunction();
10266 Local<Object> instance = function;
10267 v8::TryCatch try_catch(isolate);
10269 CHECK(instance->IsCallable());
10270 CHECK(!try_catch.HasCaught());
10275 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
10276 v8::HandleScope scope(isolate);
10277 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
10278 for (int i = 0; i < iterations; i++) {
10279 Local<v8::Number> n(v8::Integer::New(isolate, 42));
10281 return Recurse(isolate, depth - 1, iterations);
10285 THREADED_TEST(HandleIteration) {
10286 static const int kIterations = 500;
10287 static const int kNesting = 200;
10288 LocalContext context;
10289 v8::Isolate* isolate = context->GetIsolate();
10290 v8::HandleScope scope0(isolate);
10291 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10293 v8::HandleScope scope1(isolate);
10294 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10295 for (int i = 0; i < kIterations; i++) {
10296 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
10297 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
10300 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
10302 v8::HandleScope scope2(CcTest::isolate());
10303 for (int j = 0; j < kIterations; j++) {
10304 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
10305 CHECK_EQ(j + 1 + kIterations,
10306 v8::HandleScope::NumberOfHandles(isolate));
10309 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
10311 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10312 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
10316 static void InterceptorCallICFastApi(
10317 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
10318 ApiTestFuzzer::Fuzz();
10319 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
10321 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
10323 if ((*call_count) % 20 == 0) {
10324 CcTest::heap()->CollectAllGarbage();
10328 static void FastApiCallback_TrivialSignature(
10329 const v8::FunctionCallbackInfo<v8::Value>& args) {
10330 ApiTestFuzzer::Fuzz();
10331 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
10332 v8::Isolate* isolate = CcTest::isolate();
10333 CHECK_EQ(isolate, args.GetIsolate());
10334 CHECK(args.This()->Equals(args.Holder()));
10335 CHECK(args.Data()->Equals(v8_str("method_data")));
10336 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10339 static void FastApiCallback_SimpleSignature(
10340 const v8::FunctionCallbackInfo<v8::Value>& args) {
10341 ApiTestFuzzer::Fuzz();
10342 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
10343 v8::Isolate* isolate = CcTest::isolate();
10344 CHECK_EQ(isolate, args.GetIsolate());
10345 CHECK(args.This()->GetPrototype()->Equals(args.Holder()));
10346 CHECK(args.Data()->Equals(v8_str("method_data")));
10347 // Note, we're using HasRealNamedProperty instead of Has to avoid
10348 // invoking the interceptor again.
10349 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
10350 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10354 // Helper to maximize the odds of object moving.
10355 static void GenerateSomeGarbage() {
10358 "for (var i = 0; i < 1000; i++) {"
10359 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
10361 "garbage = undefined;");
10365 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
10366 static int count = 0;
10367 if (count++ % 3 == 0) {
10368 CcTest::heap()->CollectAllGarbage();
10369 // This should move the stub
10370 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
10375 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
10376 LocalContext context;
10377 v8::Isolate* isolate = context->GetIsolate();
10378 v8::HandleScope scope(isolate);
10379 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
10380 v8::ObjectTemplate::New(isolate);
10381 nativeobject_templ->Set(isolate, "callback",
10382 v8::FunctionTemplate::New(isolate,
10383 DirectApiCallback));
10384 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10385 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10386 // call the api function multiple times to ensure direct call stub creation.
10389 " for (var i = 1; i <= 30; i++) {"
10390 " nativeobject.callback();"
10397 void ThrowingDirectApiCallback(
10398 const v8::FunctionCallbackInfo<v8::Value>& args) {
10399 args.GetIsolate()->ThrowException(v8_str("g"));
10403 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
10404 LocalContext context;
10405 v8::Isolate* isolate = context->GetIsolate();
10406 v8::HandleScope scope(isolate);
10407 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
10408 v8::ObjectTemplate::New(isolate);
10409 nativeobject_templ->Set(isolate, "callback",
10410 v8::FunctionTemplate::New(isolate,
10411 ThrowingDirectApiCallback));
10412 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10413 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10414 // call the api function multiple times to ensure direct call stub creation.
10415 v8::Handle<Value> result = CompileRun(
10418 " for (var i = 1; i <= 5; i++) {"
10419 " try { nativeobject.callback(); } catch (e) { result += e; }"
10423 CHECK(v8_str("ggggg")->Equals(result));
10427 static int p_getter_count_3;
10430 static Handle<Value> DoDirectGetter() {
10431 if (++p_getter_count_3 % 3 == 0) {
10432 CcTest::heap()->CollectAllGarbage();
10433 GenerateSomeGarbage();
10435 return v8_str("Direct Getter Result");
10439 static void DirectGetterCallback(
10440 Local<String> name,
10441 const v8::PropertyCallbackInfo<v8::Value>& info) {
10442 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
10443 info.GetReturnValue().Set(DoDirectGetter());
10447 template<typename Accessor>
10448 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
10449 LocalContext context;
10450 v8::Isolate* isolate = context->GetIsolate();
10451 v8::HandleScope scope(isolate);
10452 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
10453 obj->SetAccessor(v8_str("p1"), accessor);
10454 context->Global()->Set(v8_str("o1"), obj->NewInstance());
10455 p_getter_count_3 = 0;
10456 v8::Handle<v8::Value> result = CompileRun(
10458 " for (var i = 0; i < 30; i++) o1.p1;"
10462 CHECK(v8_str("Direct Getter Result")->Equals(result));
10463 CHECK_EQ(31, p_getter_count_3);
10467 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
10468 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
10472 void ThrowingDirectGetterCallback(
10473 Local<String> name,
10474 const v8::PropertyCallbackInfo<v8::Value>& info) {
10475 info.GetIsolate()->ThrowException(v8_str("g"));
10479 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
10480 LocalContext context;
10481 v8::Isolate* isolate = context->GetIsolate();
10482 v8::HandleScope scope(isolate);
10483 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
10484 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
10485 context->Global()->Set(v8_str("o1"), obj->NewInstance());
10486 v8::Handle<Value> result = CompileRun(
10488 "for (var i = 0; i < 5; i++) {"
10489 " try { o1.p1; } catch (e) { result += e; }"
10492 CHECK(v8_str("ggggg")->Equals(result));
10496 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
10497 int interceptor_call_count = 0;
10498 v8::Isolate* isolate = CcTest::isolate();
10499 v8::HandleScope scope(isolate);
10500 v8::Handle<v8::FunctionTemplate> fun_templ =
10501 v8::FunctionTemplate::New(isolate);
10502 v8::Handle<v8::FunctionTemplate> method_templ =
10503 v8::FunctionTemplate::New(isolate,
10504 FastApiCallback_TrivialSignature,
10505 v8_str("method_data"),
10506 v8::Handle<v8::Signature>());
10507 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10508 proto_templ->Set(v8_str("method"), method_templ);
10509 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10510 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10511 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10512 v8::External::New(isolate, &interceptor_call_count)));
10513 LocalContext context;
10514 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10515 GenerateSomeGarbage();
10516 context->Global()->Set(v8_str("o"), fun->NewInstance());
10519 "for (var i = 0; i < 100; i++) {"
10520 " result = o.method(41);"
10522 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10523 CHECK_EQ(100, interceptor_call_count);
10527 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
10528 int interceptor_call_count = 0;
10529 v8::Isolate* isolate = CcTest::isolate();
10530 v8::HandleScope scope(isolate);
10531 v8::Handle<v8::FunctionTemplate> fun_templ =
10532 v8::FunctionTemplate::New(isolate);
10533 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10534 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10535 v8::Signature::New(isolate, fun_templ));
10536 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10537 proto_templ->Set(v8_str("method"), method_templ);
10538 fun_templ->SetHiddenPrototype(true);
10539 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10540 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10541 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10542 v8::External::New(isolate, &interceptor_call_count)));
10543 LocalContext context;
10544 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10545 GenerateSomeGarbage();
10546 context->Global()->Set(v8_str("o"), fun->NewInstance());
10549 "var receiver = {};"
10550 "receiver.__proto__ = o;"
10552 "for (var i = 0; i < 100; i++) {"
10553 " result = receiver.method(41);"
10555 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10556 CHECK_EQ(100, interceptor_call_count);
10560 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
10561 int interceptor_call_count = 0;
10562 v8::Isolate* isolate = CcTest::isolate();
10563 v8::HandleScope scope(isolate);
10564 v8::Handle<v8::FunctionTemplate> fun_templ =
10565 v8::FunctionTemplate::New(isolate);
10566 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10567 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10568 v8::Signature::New(isolate, fun_templ));
10569 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10570 proto_templ->Set(v8_str("method"), method_templ);
10571 fun_templ->SetHiddenPrototype(true);
10572 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10573 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10574 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10575 v8::External::New(isolate, &interceptor_call_count)));
10576 LocalContext context;
10577 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10578 GenerateSomeGarbage();
10579 context->Global()->Set(v8_str("o"), fun->NewInstance());
10582 "var receiver = {};"
10583 "receiver.__proto__ = o;"
10585 "var saved_result = 0;"
10586 "for (var i = 0; i < 100; i++) {"
10587 " result = receiver.method(41);"
10589 " saved_result = result;"
10590 " receiver = {method: function(x) { return x - 1 }};"
10593 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10594 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10595 CHECK_GE(interceptor_call_count, 50);
10599 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
10600 int interceptor_call_count = 0;
10601 v8::Isolate* isolate = CcTest::isolate();
10602 v8::HandleScope scope(isolate);
10603 v8::Handle<v8::FunctionTemplate> fun_templ =
10604 v8::FunctionTemplate::New(isolate);
10605 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10606 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10607 v8::Signature::New(isolate, fun_templ));
10608 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10609 proto_templ->Set(v8_str("method"), method_templ);
10610 fun_templ->SetHiddenPrototype(true);
10611 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10612 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10613 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10614 v8::External::New(isolate, &interceptor_call_count)));
10615 LocalContext context;
10616 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10617 GenerateSomeGarbage();
10618 context->Global()->Set(v8_str("o"), fun->NewInstance());
10621 "var receiver = {};"
10622 "receiver.__proto__ = o;"
10624 "var saved_result = 0;"
10625 "for (var i = 0; i < 100; i++) {"
10626 " result = receiver.method(41);"
10628 " saved_result = result;"
10629 " o.method = function(x) { return x - 1 };"
10632 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10633 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10634 CHECK_GE(interceptor_call_count, 50);
10638 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
10639 int interceptor_call_count = 0;
10640 v8::Isolate* isolate = CcTest::isolate();
10641 v8::HandleScope scope(isolate);
10642 v8::Handle<v8::FunctionTemplate> fun_templ =
10643 v8::FunctionTemplate::New(isolate);
10644 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10645 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10646 v8::Signature::New(isolate, fun_templ));
10647 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10648 proto_templ->Set(v8_str("method"), method_templ);
10649 fun_templ->SetHiddenPrototype(true);
10650 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10651 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10652 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10653 v8::External::New(isolate, &interceptor_call_count)));
10654 LocalContext context;
10655 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10656 GenerateSomeGarbage();
10657 context->Global()->Set(v8_str("o"), fun->NewInstance());
10658 v8::TryCatch try_catch(isolate);
10661 "var receiver = {};"
10662 "receiver.__proto__ = o;"
10664 "var saved_result = 0;"
10665 "for (var i = 0; i < 100; i++) {"
10666 " result = receiver.method(41);"
10668 " saved_result = result;"
10672 CHECK(try_catch.HasCaught());
10673 // TODO(verwaest): Adjust message.
10674 CHECK(v8_str("TypeError: receiver.method is not a function")
10675 ->Equals(try_catch.Exception()->ToString(isolate)));
10676 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10677 CHECK_GE(interceptor_call_count, 50);
10681 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
10682 int interceptor_call_count = 0;
10683 v8::Isolate* isolate = CcTest::isolate();
10684 v8::HandleScope scope(isolate);
10685 v8::Handle<v8::FunctionTemplate> fun_templ =
10686 v8::FunctionTemplate::New(isolate);
10687 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10688 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10689 v8::Signature::New(isolate, fun_templ));
10690 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10691 proto_templ->Set(v8_str("method"), method_templ);
10692 fun_templ->SetHiddenPrototype(true);
10693 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10694 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10695 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10696 v8::External::New(isolate, &interceptor_call_count)));
10697 LocalContext context;
10698 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10699 GenerateSomeGarbage();
10700 context->Global()->Set(v8_str("o"), fun->NewInstance());
10701 v8::TryCatch try_catch(isolate);
10704 "var receiver = {};"
10705 "receiver.__proto__ = o;"
10707 "var saved_result = 0;"
10708 "for (var i = 0; i < 100; i++) {"
10709 " result = receiver.method(41);"
10711 " saved_result = result;"
10712 " receiver = {method: receiver.method};"
10715 CHECK(try_catch.HasCaught());
10716 CHECK(v8_str("TypeError: Illegal invocation")
10717 ->Equals(try_catch.Exception()->ToString(isolate)));
10718 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10719 CHECK_GE(interceptor_call_count, 50);
10723 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
10724 v8::Isolate* isolate = CcTest::isolate();
10725 v8::HandleScope scope(isolate);
10726 v8::Handle<v8::FunctionTemplate> fun_templ =
10727 v8::FunctionTemplate::New(isolate);
10728 v8::Handle<v8::FunctionTemplate> method_templ =
10729 v8::FunctionTemplate::New(isolate,
10730 FastApiCallback_TrivialSignature,
10731 v8_str("method_data"),
10732 v8::Handle<v8::Signature>());
10733 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10734 proto_templ->Set(v8_str("method"), method_templ);
10735 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10737 LocalContext context;
10738 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10739 GenerateSomeGarbage();
10740 context->Global()->Set(v8_str("o"), fun->NewInstance());
10743 "for (var i = 0; i < 100; i++) {"
10744 " result = o.method(41);"
10747 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10751 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
10752 v8::Isolate* isolate = CcTest::isolate();
10753 v8::HandleScope scope(isolate);
10754 v8::Handle<v8::FunctionTemplate> fun_templ =
10755 v8::FunctionTemplate::New(isolate);
10756 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10757 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10758 v8::Signature::New(isolate, fun_templ));
10759 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10760 proto_templ->Set(v8_str("method"), method_templ);
10761 fun_templ->SetHiddenPrototype(true);
10762 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10763 CHECK(!templ.IsEmpty());
10764 LocalContext context;
10765 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10766 GenerateSomeGarbage();
10767 context->Global()->Set(v8_str("o"), fun->NewInstance());
10770 "var receiver = {};"
10771 "receiver.__proto__ = o;"
10773 "for (var i = 0; i < 100; i++) {"
10774 " result = receiver.method(41);"
10777 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10781 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
10782 v8::Isolate* isolate = CcTest::isolate();
10783 v8::HandleScope scope(isolate);
10784 v8::Handle<v8::FunctionTemplate> fun_templ =
10785 v8::FunctionTemplate::New(isolate);
10786 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10787 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10788 v8::Signature::New(isolate, fun_templ));
10789 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10790 proto_templ->Set(v8_str("method"), method_templ);
10791 fun_templ->SetHiddenPrototype(true);
10792 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10793 CHECK(!templ.IsEmpty());
10794 LocalContext context;
10795 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10796 GenerateSomeGarbage();
10797 context->Global()->Set(v8_str("o"), fun->NewInstance());
10800 "var receiver = {};"
10801 "receiver.__proto__ = o;"
10803 "var saved_result = 0;"
10804 "for (var i = 0; i < 100; i++) {"
10805 " result = receiver.method(41);"
10807 " saved_result = result;"
10808 " receiver = {method: function(x) { return x - 1 }};"
10811 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10812 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10816 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
10817 v8::Isolate* isolate = CcTest::isolate();
10818 v8::HandleScope scope(isolate);
10819 v8::Handle<v8::FunctionTemplate> fun_templ =
10820 v8::FunctionTemplate::New(isolate);
10821 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10822 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10823 v8::Signature::New(isolate, fun_templ));
10824 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10825 proto_templ->Set(v8_str("method"), method_templ);
10826 fun_templ->SetHiddenPrototype(true);
10827 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10828 CHECK(!templ.IsEmpty());
10829 LocalContext context;
10830 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10831 GenerateSomeGarbage();
10832 context->Global()->Set(v8_str("o"), fun->NewInstance());
10833 v8::TryCatch try_catch(isolate);
10836 "var receiver = {};"
10837 "receiver.__proto__ = o;"
10839 "var saved_result = 0;"
10840 "for (var i = 0; i < 100; i++) {"
10841 " result = receiver.method(41);"
10843 " saved_result = result;"
10847 CHECK(try_catch.HasCaught());
10848 // TODO(verwaest): Adjust message.
10849 CHECK(v8_str("TypeError: receiver.method is not a function")
10850 ->Equals(try_catch.Exception()->ToString(isolate)));
10851 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10855 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
10856 v8::Isolate* isolate = CcTest::isolate();
10857 v8::HandleScope scope(isolate);
10858 v8::Handle<v8::FunctionTemplate> fun_templ =
10859 v8::FunctionTemplate::New(isolate);
10860 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10861 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10862 v8::Signature::New(isolate, fun_templ));
10863 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10864 proto_templ->Set(v8_str("method"), method_templ);
10865 fun_templ->SetHiddenPrototype(true);
10866 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10867 CHECK(!templ.IsEmpty());
10868 LocalContext context;
10869 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10870 GenerateSomeGarbage();
10871 context->Global()->Set(v8_str("o"), fun->NewInstance());
10872 v8::TryCatch try_catch(isolate);
10875 "var receiver = {};"
10876 "receiver.__proto__ = o;"
10878 "var saved_result = 0;"
10879 "for (var i = 0; i < 100; i++) {"
10880 " result = receiver.method(41);"
10882 " saved_result = result;"
10883 " receiver = Object.create(receiver);"
10886 CHECK(try_catch.HasCaught());
10887 CHECK(v8_str("TypeError: Illegal invocation")
10888 ->Equals(try_catch.Exception()->ToString(isolate)));
10889 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10893 static void ThrowingGetter(Local<String> name,
10894 const v8::PropertyCallbackInfo<v8::Value>& info) {
10895 ApiTestFuzzer::Fuzz();
10896 info.GetIsolate()->ThrowException(Handle<Value>());
10897 info.GetReturnValue().SetUndefined();
10901 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10902 LocalContext context;
10903 HandleScope scope(context->GetIsolate());
10905 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
10906 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10907 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10909 Local<Object> instance = templ->GetFunction()->NewInstance();
10911 Local<Object> another = Object::New(context->GetIsolate());
10912 another->SetPrototype(instance);
10914 Local<Object> with_js_getter = CompileRun(
10916 "o.__defineGetter__('f', function() { throw undefined; });\n"
10917 "o\n").As<Object>();
10918 CHECK(!with_js_getter.IsEmpty());
10920 TryCatch try_catch(context->GetIsolate());
10922 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10923 CHECK(try_catch.HasCaught());
10925 CHECK(result.IsEmpty());
10927 Maybe<PropertyAttribute> attr =
10928 instance->GetRealNamedPropertyAttributes(v8_str("f"));
10929 CHECK(!try_catch.HasCaught());
10930 CHECK(Just(None) == attr);
10932 result = another->GetRealNamedProperty(v8_str("f"));
10933 CHECK(try_catch.HasCaught());
10935 CHECK(result.IsEmpty());
10937 attr = another->GetRealNamedPropertyAttributes(v8_str("f"));
10938 CHECK(!try_catch.HasCaught());
10939 CHECK(Just(None) == attr);
10941 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10942 CHECK(try_catch.HasCaught());
10944 CHECK(result.IsEmpty());
10946 attr = another->GetRealNamedPropertyAttributesInPrototypeChain(v8_str("f"));
10947 CHECK(!try_catch.HasCaught());
10948 CHECK(Just(None) == attr);
10950 result = another->Get(v8_str("f"));
10951 CHECK(try_catch.HasCaught());
10953 CHECK(result.IsEmpty());
10955 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10956 CHECK(try_catch.HasCaught());
10958 CHECK(result.IsEmpty());
10960 attr = with_js_getter->GetRealNamedPropertyAttributes(v8_str("f"));
10961 CHECK(!try_catch.HasCaught());
10962 CHECK(Just(None) == attr);
10964 result = with_js_getter->Get(v8_str("f"));
10965 CHECK(try_catch.HasCaught());
10967 CHECK(result.IsEmpty());
10971 static void ThrowingCallbackWithTryCatch(
10972 const v8::FunctionCallbackInfo<v8::Value>& args) {
10973 TryCatch try_catch(args.GetIsolate());
10974 // Verboseness is important: it triggers message delivery which can call into
10976 try_catch.SetVerbose(true);
10977 CompileRun("throw 'from JS';");
10978 CHECK(try_catch.HasCaught());
10979 CHECK(!CcTest::i_isolate()->has_pending_exception());
10980 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
10984 static int call_depth;
10987 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10988 TryCatch try_catch(CcTest::isolate());
10992 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
10993 if (--call_depth) CompileRun("throw 'ThrowInJS';");
10997 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
10998 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
11002 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
11003 Handle<String> errorMessageString = message->Get();
11004 CHECK(!errorMessageString.IsEmpty());
11005 message->GetStackTrace();
11006 message->GetScriptOrigin().ResourceName();
11010 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
11011 LocalContext context;
11012 v8::Isolate* isolate = context->GetIsolate();
11013 HandleScope scope(isolate);
11015 Local<Function> func =
11016 FunctionTemplate::New(isolate,
11017 ThrowingCallbackWithTryCatch)->GetFunction();
11018 context->Global()->Set(v8_str("func"), func);
11020 MessageCallback callbacks[] =
11021 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
11022 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
11023 MessageCallback callback = callbacks[i];
11024 if (callback != NULL) {
11025 V8::AddMessageListener(callback);
11027 // Some small number to control number of times message handler should
11028 // throw an exception.
11031 "var thrown = false;\n"
11032 "try { func(); } catch(e) { thrown = true; }\n"
11034 if (callback != NULL) {
11035 V8::RemoveMessageListeners(callback);
11041 static void ParentGetter(Local<String> name,
11042 const v8::PropertyCallbackInfo<v8::Value>& info) {
11043 ApiTestFuzzer::Fuzz();
11044 info.GetReturnValue().Set(v8_num(1));
11048 static void ChildGetter(Local<String> name,
11049 const v8::PropertyCallbackInfo<v8::Value>& info) {
11050 ApiTestFuzzer::Fuzz();
11051 info.GetReturnValue().Set(v8_num(42));
11055 THREADED_TEST(Overriding) {
11056 LocalContext context;
11057 v8::Isolate* isolate = context->GetIsolate();
11058 v8::HandleScope scope(isolate);
11060 // Parent template.
11061 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
11062 Local<ObjectTemplate> parent_instance_templ =
11063 parent_templ->InstanceTemplate();
11064 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
11066 // Template that inherits from the parent template.
11067 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
11068 Local<ObjectTemplate> child_instance_templ =
11069 child_templ->InstanceTemplate();
11070 child_templ->Inherit(parent_templ);
11071 // Override 'f'. The child version of 'f' should get called for child
11073 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
11074 // Add 'g' twice. The 'g' added last should get called for instances.
11075 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
11076 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
11078 // Add 'h' as an accessor to the proto template with ReadOnly attributes
11079 // so 'h' can be shadowed on the instance object.
11080 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
11081 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
11082 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11084 // Add 'i' as an accessor to the instance template with ReadOnly attributes
11085 // but the attribute does not have effect because it is duplicated with
11087 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
11088 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11092 // Instantiate the child template.
11093 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
11095 // Check that the child function overrides the parent one.
11096 context->Global()->Set(v8_str("o"), instance);
11097 Local<Value> value = v8_compile("o.f")->Run();
11098 // Check that the 'g' that was added last is hit.
11099 CHECK_EQ(42, value->Int32Value());
11100 value = v8_compile("o.g")->Run();
11101 CHECK_EQ(42, value->Int32Value());
11103 // Check that 'h' cannot be shadowed.
11104 value = v8_compile("o.h = 3; o.h")->Run();
11105 CHECK_EQ(1, value->Int32Value());
11107 // Check that 'i' cannot be shadowed or changed.
11108 value = v8_compile("o.i = 3; o.i")->Run();
11109 CHECK_EQ(42, value->Int32Value());
11113 static void IsConstructHandler(
11114 const v8::FunctionCallbackInfo<v8::Value>& args) {
11115 ApiTestFuzzer::Fuzz();
11116 args.GetReturnValue().Set(args.IsConstructCall());
11120 THREADED_TEST(IsConstructCall) {
11121 v8::Isolate* isolate = CcTest::isolate();
11122 v8::HandleScope scope(isolate);
11124 // Function template with call handler.
11125 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11126 templ->SetCallHandler(IsConstructHandler);
11128 LocalContext context;
11130 context->Global()->Set(v8_str("f"), templ->GetFunction());
11131 Local<Value> value = v8_compile("f()")->Run();
11132 CHECK(!value->BooleanValue());
11133 value = v8_compile("new f()")->Run();
11134 CHECK(value->BooleanValue());
11138 THREADED_TEST(ObjectProtoToString) {
11139 v8::Isolate* isolate = CcTest::isolate();
11140 v8::HandleScope scope(isolate);
11141 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11142 templ->SetClassName(v8_str("MyClass"));
11144 LocalContext context;
11146 Local<String> customized_tostring = v8_str("customized toString");
11148 // Replace Object.prototype.toString
11149 v8_compile("Object.prototype.toString = function() {"
11150 " return 'customized toString';"
11153 // Normal ToString call should call replaced Object.prototype.toString
11154 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11155 Local<String> value = instance->ToString(isolate);
11156 CHECK(value->IsString() && value->Equals(customized_tostring));
11158 // ObjectProtoToString should not call replace toString function.
11159 value = instance->ObjectProtoToString();
11160 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11163 value = context->Global()->ObjectProtoToString();
11164 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11166 // Check ordinary object
11167 Local<Value> object = v8_compile("new Object()")->Run();
11168 value = object.As<v8::Object>()->ObjectProtoToString();
11169 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11173 TEST(ObjectProtoToStringES6) {
11174 // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
11175 i::FLAG_harmony_tostring = true;
11176 LocalContext context;
11177 v8::Isolate* isolate = CcTest::isolate();
11178 v8::HandleScope scope(isolate);
11179 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11180 templ->SetClassName(v8_str("MyClass"));
11182 Local<String> customized_tostring = v8_str("customized toString");
11184 // Replace Object.prototype.toString
11186 "Object.prototype.toString = function() {"
11187 " return 'customized toString';"
11190 // Normal ToString call should call replaced Object.prototype.toString
11191 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11192 Local<String> value = instance->ToString(isolate);
11193 CHECK(value->IsString() && value->Equals(customized_tostring));
11195 // ObjectProtoToString should not call replace toString function.
11196 value = instance->ObjectProtoToString();
11197 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11200 value = context->Global()->ObjectProtoToString();
11201 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11203 // Check ordinary object
11204 Local<Value> object = CompileRun("new Object()");
11205 value = object.As<v8::Object>()->ObjectProtoToString();
11206 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11208 // Check that ES6 semantics using @@toStringTag work
11209 Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
11211 #define TEST_TOSTRINGTAG(type, tag, expected) \
11213 object = CompileRun("new " #type "()"); \
11214 object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
11215 value = object.As<v8::Object>()->ObjectProtoToString(); \
11216 CHECK(value->IsString() && \
11217 value->Equals(v8_str("[object " #expected "]"))); \
11220 TEST_TOSTRINGTAG(Array, Object, Object);
11221 TEST_TOSTRINGTAG(Object, Arguments, Arguments);
11222 TEST_TOSTRINGTAG(Object, Array, Array);
11223 TEST_TOSTRINGTAG(Object, Boolean, Boolean);
11224 TEST_TOSTRINGTAG(Object, Date, Date);
11225 TEST_TOSTRINGTAG(Object, Error, Error);
11226 TEST_TOSTRINGTAG(Object, Function, Function);
11227 TEST_TOSTRINGTAG(Object, Number, Number);
11228 TEST_TOSTRINGTAG(Object, RegExp, RegExp);
11229 TEST_TOSTRINGTAG(Object, String, String);
11230 TEST_TOSTRINGTAG(Object, Foo, Foo);
11232 #undef TEST_TOSTRINGTAG
11234 Local<v8::RegExp> valueRegExp = v8::RegExp::New(v8_str("^$"),
11235 v8::RegExp::kNone);
11236 Local<Value> valueNumber = v8_num(123);
11237 Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
11238 Local<v8::Function> valueFunction =
11239 CompileRun("(function fn() {})").As<v8::Function>();
11240 Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
11241 Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
11242 Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
11244 #define TEST_TOSTRINGTAG(type, tagValue, expected) \
11246 object = CompileRun("new " #type "()"); \
11247 object.As<v8::Object>()->Set(toStringTag, tagValue); \
11248 value = object.As<v8::Object>()->ObjectProtoToString(); \
11249 CHECK(value->IsString() && \
11250 value->Equals(v8_str("[object " #expected "]"))); \
11253 #define TEST_TOSTRINGTAG_TYPES(tagValue) \
11254 TEST_TOSTRINGTAG(Array, tagValue, Array); \
11255 TEST_TOSTRINGTAG(Object, tagValue, Object); \
11256 TEST_TOSTRINGTAG(Function, tagValue, Function); \
11257 TEST_TOSTRINGTAG(Date, tagValue, Date); \
11258 TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \
11259 TEST_TOSTRINGTAG(Error, tagValue, Error); \
11261 // Test non-String-valued @@toStringTag
11262 TEST_TOSTRINGTAG_TYPES(valueRegExp);
11263 TEST_TOSTRINGTAG_TYPES(valueNumber);
11264 TEST_TOSTRINGTAG_TYPES(valueSymbol);
11265 TEST_TOSTRINGTAG_TYPES(valueFunction);
11266 TEST_TOSTRINGTAG_TYPES(valueObject);
11267 TEST_TOSTRINGTAG_TYPES(valueNull);
11268 TEST_TOSTRINGTAG_TYPES(valueUndef);
11270 #undef TEST_TOSTRINGTAG
11271 #undef TEST_TOSTRINGTAG_TYPES
11273 // @@toStringTag getter throws
11274 Local<Value> obj = v8::Object::New(isolate);
11275 obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
11277 TryCatch try_catch(isolate);
11278 value = obj.As<v8::Object>()->ObjectProtoToString();
11279 CHECK(value.IsEmpty());
11280 CHECK(try_catch.HasCaught());
11283 // @@toStringTag getter does not throw
11284 obj = v8::Object::New(isolate);
11285 obj.As<v8::Object>()->SetAccessor(
11286 toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
11288 TryCatch try_catch(isolate);
11289 value = obj.As<v8::Object>()->ObjectProtoToString();
11290 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11291 CHECK(!try_catch.HasCaught());
11294 // JS @@toStringTag value
11295 obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
11297 TryCatch try_catch(isolate);
11298 value = obj.As<v8::Object>()->ObjectProtoToString();
11299 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11300 CHECK(!try_catch.HasCaught());
11303 // JS @@toStringTag getter throws
11305 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
11306 " get: function() { throw 'Test'; }"
11309 TryCatch try_catch(isolate);
11310 value = obj.As<v8::Object>()->ObjectProtoToString();
11311 CHECK(value.IsEmpty());
11312 CHECK(try_catch.HasCaught());
11315 // JS @@toStringTag getter does not throw
11317 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
11318 " get: function() { return 'Test'; }"
11321 TryCatch try_catch(isolate);
11322 value = obj.As<v8::Object>()->ObjectProtoToString();
11323 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11324 CHECK(!try_catch.HasCaught());
11329 THREADED_TEST(ObjectGetConstructorName) {
11330 v8::Isolate* isolate = CcTest::isolate();
11331 LocalContext context;
11332 v8::HandleScope scope(isolate);
11334 "function Parent() {};"
11335 "function Child() {};"
11336 "Child.prototype = new Parent();"
11337 "var outer = { inner: function() { } };"
11338 "var p = new Parent();"
11339 "var c = new Child();"
11340 "var x = new outer.inner();"
11341 "var proto = Child.prototype;")->Run();
11343 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
11344 CHECK(p->IsObject() &&
11345 p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
11347 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
11348 CHECK(c->IsObject() &&
11349 c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
11351 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
11352 CHECK(x->IsObject() &&
11353 x->ToObject(isolate)->GetConstructorName()->Equals(
11354 v8_str("outer.inner")));
11356 Local<v8::Value> child_prototype = context->Global()->Get(v8_str("proto"));
11357 CHECK(child_prototype->IsObject() &&
11358 child_prototype->ToObject(isolate)->GetConstructorName()->Equals(
11359 v8_str("Parent")));
11363 bool ApiTestFuzzer::fuzzing_ = false;
11364 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
11365 int ApiTestFuzzer::active_tests_;
11366 int ApiTestFuzzer::tests_being_run_;
11367 int ApiTestFuzzer::current_;
11370 // We are in a callback and want to switch to another thread (if we
11371 // are currently running the thread fuzzing test).
11372 void ApiTestFuzzer::Fuzz() {
11373 if (!fuzzing_) return;
11374 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
11375 test->ContextSwitch();
11379 // Let the next thread go. Since it is also waiting on the V8 lock it may
11380 // not start immediately.
11381 bool ApiTestFuzzer::NextThread() {
11382 int test_position = GetNextTestNumber();
11383 const char* test_name = RegisterThreadedTest::nth(current_)->name();
11384 if (test_position == current_) {
11386 printf("Stay with %s\n", test_name);
11389 if (kLogThreading) {
11390 printf("Switch from %s to %s\n",
11392 RegisterThreadedTest::nth(test_position)->name());
11394 current_ = test_position;
11395 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
11400 void ApiTestFuzzer::Run() {
11401 // When it is our turn...
11404 // ... get the V8 lock and start running the test.
11405 v8::Locker locker(CcTest::isolate());
11408 // This test finished.
11411 // If it was the last then signal that fact.
11412 if (active_tests_ == 0) {
11413 all_tests_done_.Signal();
11415 // Otherwise select a new test and start that.
11421 static unsigned linear_congruential_generator;
11424 void ApiTestFuzzer::SetUp(PartOfTest part) {
11425 linear_congruential_generator = i::FLAG_testing_prng_seed;
11427 int count = RegisterThreadedTest::count();
11428 int start = count * part / (LAST_PART + 1);
11429 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
11430 active_tests_ = tests_being_run_ = end - start + 1;
11431 for (int i = 0; i < tests_being_run_; i++) {
11432 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
11434 for (int i = 0; i < active_tests_; i++) {
11435 RegisterThreadedTest::nth(i)->fuzzer_->Start();
11440 static void CallTestNumber(int test_number) {
11441 (RegisterThreadedTest::nth(test_number)->callback())();
11445 void ApiTestFuzzer::RunAllTests() {
11446 // Set off the first test.
11449 // Wait till they are all done.
11450 all_tests_done_.Wait();
11454 int ApiTestFuzzer::GetNextTestNumber() {
11457 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
11458 linear_congruential_generator *= 1664525u;
11459 linear_congruential_generator += 1013904223u;
11460 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
11465 void ApiTestFuzzer::ContextSwitch() {
11466 // If the new thread is the same as the current thread there is nothing to do.
11467 if (NextThread()) {
11468 // Now it can start.
11469 v8::Unlocker unlocker(CcTest::isolate());
11470 // Wait till someone starts us again.
11477 void ApiTestFuzzer::TearDown() {
11479 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
11480 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
11481 if (fuzzer != NULL) fuzzer->Join();
11486 // Lets not be needlessly self-referential.
11488 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
11489 ApiTestFuzzer::RunAllTests();
11490 ApiTestFuzzer::TearDown();
11495 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
11496 ApiTestFuzzer::RunAllTests();
11497 ApiTestFuzzer::TearDown();
11502 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
11503 ApiTestFuzzer::RunAllTests();
11504 ApiTestFuzzer::TearDown();
11509 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
11510 ApiTestFuzzer::RunAllTests();
11511 ApiTestFuzzer::TearDown();
11515 void ApiTestFuzzer::CallTest() {
11516 v8::Isolate::Scope scope(CcTest::isolate());
11518 printf("Start test %d\n", test_number_);
11519 CallTestNumber(test_number_);
11521 printf("End test %d\n", test_number_);
11525 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
11526 v8::Isolate* isolate = args.GetIsolate();
11527 CHECK(v8::Locker::IsLocked(isolate));
11528 ApiTestFuzzer::Fuzz();
11529 v8::Unlocker unlocker(isolate);
11530 const char* code = "throw 7;";
11532 v8::Locker nested_locker(isolate);
11533 v8::HandleScope scope(isolate);
11534 v8::Handle<Value> exception;
11536 v8::TryCatch try_catch(isolate);
11537 v8::Handle<Value> value = CompileRun(code);
11538 CHECK(value.IsEmpty());
11539 CHECK(try_catch.HasCaught());
11540 // Make sure to wrap the exception in a new handle because
11541 // the handle returned from the TryCatch is destroyed
11542 // when the TryCatch is destroyed.
11543 exception = Local<Value>::New(isolate, try_catch.Exception());
11545 args.GetIsolate()->ThrowException(exception);
11550 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
11551 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
11552 ApiTestFuzzer::Fuzz();
11553 v8::Unlocker unlocker(CcTest::isolate());
11554 const char* code = "throw 7;";
11556 v8::Locker nested_locker(CcTest::isolate());
11557 v8::HandleScope scope(args.GetIsolate());
11558 v8::Handle<Value> value = CompileRun(code);
11559 CHECK(value.IsEmpty());
11560 args.GetReturnValue().Set(v8_str("foo"));
11565 // These are locking tests that don't need to be run again
11566 // as part of the locking aggregation tests.
11567 TEST(NestedLockers) {
11568 v8::Isolate* isolate = CcTest::isolate();
11569 v8::Locker locker(isolate);
11570 CHECK(v8::Locker::IsLocked(isolate));
11572 v8::HandleScope scope(env->GetIsolate());
11573 Local<v8::FunctionTemplate> fun_templ =
11574 v8::FunctionTemplate::New(isolate, ThrowInJS);
11575 Local<Function> fun = fun_templ->GetFunction();
11576 env->Global()->Set(v8_str("throw_in_js"), fun);
11577 Local<Script> script = v8_compile("(function () {"
11585 CHECK_EQ(91, script->Run()->Int32Value());
11589 // These are locking tests that don't need to be run again
11590 // as part of the locking aggregation tests.
11591 TEST(NestedLockersNoTryCatch) {
11592 v8::Locker locker(CcTest::isolate());
11594 v8::HandleScope scope(env->GetIsolate());
11595 Local<v8::FunctionTemplate> fun_templ =
11596 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
11597 Local<Function> fun = fun_templ->GetFunction();
11598 env->Global()->Set(v8_str("throw_in_js"), fun);
11599 Local<Script> script = v8_compile("(function () {"
11607 CHECK_EQ(91, script->Run()->Int32Value());
11611 THREADED_TEST(RecursiveLocking) {
11612 v8::Locker locker(CcTest::isolate());
11614 v8::Locker locker2(CcTest::isolate());
11615 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
11620 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
11621 ApiTestFuzzer::Fuzz();
11622 v8::Unlocker unlocker(CcTest::isolate());
11626 THREADED_TEST(LockUnlockLock) {
11628 v8::Locker locker(CcTest::isolate());
11629 v8::HandleScope scope(CcTest::isolate());
11631 Local<v8::FunctionTemplate> fun_templ =
11632 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
11633 Local<Function> fun = fun_templ->GetFunction();
11634 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11635 Local<Script> script = v8_compile("(function () {"
11636 " unlock_for_a_moment();"
11639 CHECK_EQ(42, script->Run()->Int32Value());
11642 v8::Locker locker(CcTest::isolate());
11643 v8::HandleScope scope(CcTest::isolate());
11645 Local<v8::FunctionTemplate> fun_templ =
11646 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
11647 Local<Function> fun = fun_templ->GetFunction();
11648 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11649 Local<Script> script = v8_compile("(function () {"
11650 " unlock_for_a_moment();"
11653 CHECK_EQ(42, script->Run()->Int32Value());
11658 static int GetGlobalObjectsCount() {
11660 i::HeapIterator it(CcTest::heap());
11661 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
11662 if (object->IsJSGlobalObject()) count++;
11667 static void CheckSurvivingGlobalObjectsCount(int expected) {
11668 // We need to collect all garbage twice to be sure that everything
11669 // has been collected. This is because inline caches are cleared in
11670 // the first garbage collection but some of the maps have already
11671 // been marked at that point. Therefore some of the maps are not
11672 // collected until the second garbage collection.
11673 CcTest::heap()->CollectAllGarbage();
11674 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
11675 int count = GetGlobalObjectsCount();
11677 if (count != expected) CcTest::heap()->TracePathToGlobal();
11679 CHECK_EQ(expected, count);
11683 TEST(DontLeakGlobalObjects) {
11684 // Regression test for issues 1139850 and 1174891.
11686 i::FLAG_expose_gc = true;
11687 v8::V8::Initialize();
11689 for (int i = 0; i < 5; i++) {
11690 { v8::HandleScope scope(CcTest::isolate());
11691 LocalContext context;
11693 CcTest::isolate()->ContextDisposedNotification();
11694 CheckSurvivingGlobalObjectsCount(0);
11696 { v8::HandleScope scope(CcTest::isolate());
11697 LocalContext context;
11698 v8_compile("Date")->Run();
11700 CcTest::isolate()->ContextDisposedNotification();
11701 CheckSurvivingGlobalObjectsCount(0);
11703 { v8::HandleScope scope(CcTest::isolate());
11704 LocalContext context;
11705 v8_compile("/aaa/")->Run();
11707 CcTest::isolate()->ContextDisposedNotification();
11708 CheckSurvivingGlobalObjectsCount(0);
11710 { v8::HandleScope scope(CcTest::isolate());
11711 const char* extension_list[] = { "v8/gc" };
11712 v8::ExtensionConfiguration extensions(1, extension_list);
11713 LocalContext context(&extensions);
11714 v8_compile("gc();")->Run();
11716 CcTest::isolate()->ContextDisposedNotification();
11717 CheckSurvivingGlobalObjectsCount(0);
11722 TEST(CopyablePersistent) {
11723 LocalContext context;
11724 v8::Isolate* isolate = context->GetIsolate();
11725 i::GlobalHandles* globals =
11726 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
11727 int initial_handles = globals->global_handles_count();
11728 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
11731 CopyableObject handle1;
11733 v8::HandleScope scope(isolate);
11734 handle1.Reset(isolate, v8::Object::New(isolate));
11736 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
11737 CopyableObject handle2;
11739 CHECK(handle1 == handle2);
11740 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
11741 CopyableObject handle3(handle2);
11742 CHECK(handle1 == handle3);
11743 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
11745 // Verify autodispose
11746 CHECK_EQ(initial_handles, globals->global_handles_count());
11750 static void WeakApiCallback(
11751 const v8::WeakCallbackInfo<Persistent<v8::Object>>& data) {
11752 data.GetParameter()->Reset();
11753 delete data.GetParameter();
11757 TEST(WeakCallbackApi) {
11758 LocalContext context;
11759 v8::Isolate* isolate = context->GetIsolate();
11760 i::GlobalHandles* globals =
11761 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
11762 int initial_handles = globals->global_handles_count();
11764 v8::HandleScope scope(isolate);
11765 v8::Local<v8::Object> obj = v8::Object::New(isolate);
11766 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
11767 v8::Persistent<v8::Object>* handle =
11768 new v8::Persistent<v8::Object>(isolate, obj);
11769 handle->SetWeak<v8::Persistent<v8::Object>>(
11770 handle, WeakApiCallback, v8::WeakCallbackType::kParameter);
11772 reinterpret_cast<i::Isolate*>(isolate)->heap()->CollectAllGarbage(
11773 i::Heap::kAbortIncrementalMarkingMask);
11774 // Verify disposed.
11775 CHECK_EQ(initial_handles, globals->global_handles_count());
11779 v8::Persistent<v8::Object> some_object;
11780 v8::Persistent<v8::Object> bad_handle;
11783 void NewPersistentHandleCallback2(
11784 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11785 v8::HandleScope scope(data.GetIsolate());
11786 bad_handle.Reset(data.GetIsolate(), some_object);
11790 void NewPersistentHandleCallback1(
11791 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11792 data.GetParameter()->Reset();
11793 data.SetSecondPassCallback(NewPersistentHandleCallback2);
11797 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
11798 LocalContext context;
11799 v8::Isolate* isolate = context->GetIsolate();
11801 v8::Persistent<v8::Object> handle1, handle2;
11803 v8::HandleScope scope(isolate);
11804 some_object.Reset(isolate, v8::Object::New(isolate));
11805 handle1.Reset(isolate, v8::Object::New(isolate));
11806 handle2.Reset(isolate, v8::Object::New(isolate));
11808 // Note: order is implementation dependent alas: currently
11809 // global handle nodes are processed by PostGarbageCollectionProcessing
11810 // in reverse allocation order, so if second allocated handle is deleted,
11811 // weak callback of the first handle would be able to 'reallocate' it.
11812 handle1.SetWeak(&handle1, NewPersistentHandleCallback1,
11813 v8::WeakCallbackType::kParameter);
11815 CcTest::heap()->CollectAllGarbage();
11819 v8::Persistent<v8::Object> to_be_disposed;
11822 void DisposeAndForceGcCallback2(
11823 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11824 to_be_disposed.Reset();
11825 CcTest::heap()->CollectAllGarbage();
11829 void DisposeAndForceGcCallback1(
11830 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11831 data.GetParameter()->Reset();
11832 data.SetSecondPassCallback(DisposeAndForceGcCallback2);
11836 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11837 LocalContext context;
11838 v8::Isolate* isolate = context->GetIsolate();
11840 v8::Persistent<v8::Object> handle1, handle2;
11842 v8::HandleScope scope(isolate);
11843 handle1.Reset(isolate, v8::Object::New(isolate));
11844 handle2.Reset(isolate, v8::Object::New(isolate));
11846 handle1.SetWeak(&handle1, DisposeAndForceGcCallback1,
11847 v8::WeakCallbackType::kParameter);
11848 to_be_disposed.Reset(isolate, handle2);
11849 CcTest::heap()->CollectAllGarbage();
11852 void DisposingCallback(
11853 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11854 data.GetParameter()->Reset();
11857 void HandleCreatingCallback2(
11858 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11859 v8::HandleScope scope(data.GetIsolate());
11860 v8::Global<v8::Object>(data.GetIsolate(), v8::Object::New(data.GetIsolate()));
11864 void HandleCreatingCallback1(
11865 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
11866 data.GetParameter()->Reset();
11867 data.SetSecondPassCallback(HandleCreatingCallback2);
11871 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11872 LocalContext context;
11873 v8::Isolate* isolate = context->GetIsolate();
11875 v8::Persistent<v8::Object> handle1, handle2, handle3;
11877 v8::HandleScope scope(isolate);
11878 handle3.Reset(isolate, v8::Object::New(isolate));
11879 handle2.Reset(isolate, v8::Object::New(isolate));
11880 handle1.Reset(isolate, v8::Object::New(isolate));
11882 handle2.SetWeak(&handle2, DisposingCallback,
11883 v8::WeakCallbackType::kParameter);
11884 handle3.SetWeak(&handle3, HandleCreatingCallback1,
11885 v8::WeakCallbackType::kParameter);
11886 CcTest::heap()->CollectAllGarbage();
11890 THREADED_TEST(CheckForCrossContextObjectLiterals) {
11891 v8::V8::Initialize();
11894 const char* sources[nof] = {
11895 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11899 for (int i = 0; i < nof; i++) {
11900 const char* source = sources[i];
11901 { v8::HandleScope scope(CcTest::isolate());
11902 LocalContext context;
11903 CompileRun(source);
11905 { v8::HandleScope scope(CcTest::isolate());
11906 LocalContext context;
11907 CompileRun(source);
11913 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
11914 v8::EscapableHandleScope inner(env->GetIsolate());
11916 v8::Local<Value> three = v8_num(3);
11917 v8::Local<Value> value = inner.Escape(three);
11923 THREADED_TEST(NestedHandleScopeAndContexts) {
11924 v8::Isolate* isolate = CcTest::isolate();
11925 v8::HandleScope outer(isolate);
11926 v8::Local<Context> env = Context::New(isolate);
11928 v8::Handle<Value> value = NestedScope(env);
11929 v8::Handle<String> str(value->ToString(isolate));
11930 CHECK(!str.IsEmpty());
11935 static bool MatchPointers(void* key1, void* key2) {
11936 return key1 == key2;
11940 struct SymbolInfo {
11947 class SetFunctionEntryHookTest {
11949 SetFunctionEntryHookTest() {
11950 CHECK(instance_ == NULL);
11953 ~SetFunctionEntryHookTest() {
11954 CHECK(instance_ == this);
11959 symbol_locations_.clear();
11960 invocations_.clear();
11963 void OnJitEvent(const v8::JitCodeEvent* event);
11964 static void JitEvent(const v8::JitCodeEvent* event) {
11965 CHECK(instance_ != NULL);
11966 instance_->OnJitEvent(event);
11969 void OnEntryHook(uintptr_t function,
11970 uintptr_t return_addr_location);
11971 static void EntryHook(uintptr_t function,
11972 uintptr_t return_addr_location) {
11973 CHECK(instance_ != NULL);
11974 instance_->OnEntryHook(function, return_addr_location);
11977 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11978 CHECK(instance_ != NULL);
11979 args.GetReturnValue().Set(v8_num(42));
11981 void RunLoopInNewEnv(v8::Isolate* isolate);
11983 // Records addr as location of symbol.
11984 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
11986 // Finds the symbol containing addr
11987 SymbolInfo* FindSymbolForAddr(i::Address addr);
11988 // Returns the number of invocations where the caller name contains
11989 // \p caller_name and the function name contains \p function_name.
11990 int CountInvocations(const char* caller_name,
11991 const char* function_name);
11993 i::Handle<i::JSFunction> foo_func_;
11994 i::Handle<i::JSFunction> bar_func_;
11996 typedef std::map<size_t, SymbolInfo> SymbolMap;
11997 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
11998 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
11999 SymbolMap symbols_;
12000 SymbolLocationMap symbol_locations_;
12001 InvocationMap invocations_;
12003 static SetFunctionEntryHookTest* instance_;
12005 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
12008 // Returns true if addr is in the range [start, start+len).
12009 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
12010 if (start <= addr && start + len > addr)
12016 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
12017 SymbolInfo* symbol) {
12018 // Insert the symbol at the new location.
12019 SymbolLocationMap::iterator it =
12020 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
12021 // Now erase symbols to the left and right that overlap this one.
12022 while (it != symbol_locations_.begin()) {
12023 SymbolLocationMap::iterator left = it;
12025 if (!Overlaps(left->first, left->second->size, addr))
12027 symbol_locations_.erase(left);
12030 // Now erase symbols to the left and right that overlap this one.
12032 SymbolLocationMap::iterator right = it;
12034 if (right == symbol_locations_.end())
12036 if (!Overlaps(addr, symbol->size, right->first))
12038 symbol_locations_.erase(right);
12043 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
12044 switch (event->type) {
12045 case v8::JitCodeEvent::CODE_ADDED: {
12046 CHECK(event->code_start != NULL);
12047 CHECK_NE(0, static_cast<int>(event->code_len));
12048 CHECK(event->name.str != NULL);
12049 size_t symbol_id = symbols_.size();
12051 // Record the new symbol.
12052 SymbolInfo& info = symbols_[symbol_id];
12053 info.id = symbol_id;
12054 info.size = event->code_len;
12055 info.name.assign(event->name.str, event->name.str + event->name.len);
12057 // And record it's location.
12058 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
12062 case v8::JitCodeEvent::CODE_MOVED: {
12063 // We would like to never see code move that we haven't seen before,
12064 // but the code creation event does not happen until the line endings
12065 // have been calculated (this is so that we can report the line in the
12066 // script at which the function source is found, see
12067 // Compiler::RecordFunctionCompilation) and the line endings
12068 // calculations can cause a GC, which can move the newly created code
12069 // before its existence can be logged.
12070 SymbolLocationMap::iterator it(
12071 symbol_locations_.find(
12072 reinterpret_cast<i::Address>(event->code_start)));
12073 if (it != symbol_locations_.end()) {
12074 // Found a symbol at this location, move it.
12075 SymbolInfo* info = it->second;
12076 symbol_locations_.erase(it);
12077 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
12086 void SetFunctionEntryHookTest::OnEntryHook(
12087 uintptr_t function, uintptr_t return_addr_location) {
12088 // Get the function's code object.
12089 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
12090 reinterpret_cast<i::Address>(function));
12091 CHECK(function_code != NULL);
12093 // Then try and look up the caller's code object.
12094 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
12096 // Count the invocation.
12097 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
12098 SymbolInfo* function_symbol =
12099 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
12100 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
12102 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
12103 // Check that we have a symbol for the "bar" function at the right location.
12104 SymbolLocationMap::iterator it(
12105 symbol_locations_.find(function_code->instruction_start()));
12106 CHECK(it != symbol_locations_.end());
12109 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
12110 // Check that we have a symbol for "foo" at the right location.
12111 SymbolLocationMap::iterator it(
12112 symbol_locations_.find(function_code->instruction_start()));
12113 CHECK(it != symbol_locations_.end());
12118 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
12119 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
12120 // Do we have a direct hit on a symbol?
12121 if (it != symbol_locations_.end()) {
12122 if (it->first == addr)
12126 // If not a direct hit, it'll have to be the previous symbol.
12127 if (it == symbol_locations_.begin())
12131 size_t offs = addr - it->first;
12132 if (offs < it->second->size)
12139 int SetFunctionEntryHookTest::CountInvocations(
12140 const char* caller_name, const char* function_name) {
12141 InvocationMap::iterator it(invocations_.begin());
12142 int invocations = 0;
12143 for (; it != invocations_.end(); ++it) {
12144 SymbolInfo* caller = it->first.first;
12145 SymbolInfo* function = it->first.second;
12147 // Filter out non-matching functions.
12148 if (function_name != NULL) {
12149 if (function->name.find(function_name) == std::string::npos)
12153 // Filter out non-matching callers.
12154 if (caller_name != NULL) {
12155 if (caller == NULL)
12157 if (caller->name.find(caller_name) == std::string::npos)
12161 // It matches add the invocation count to the tally.
12162 invocations += it->second;
12165 return invocations;
12169 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
12170 v8::HandleScope outer(isolate);
12171 v8::Local<Context> env = Context::New(isolate);
12174 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
12175 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
12176 env->Global()->Set(v8_str("obj"), t->NewInstance());
12178 const char* script =
12179 "function bar() {\n"
12181 " for (i = 0; i < 100; ++i)\n"
12185 "function foo(i) { return i * i; }\n"
12186 "// Invoke on the runtime function.\n"
12188 CompileRun(script);
12189 bar_func_ = i::Handle<i::JSFunction>::cast(
12190 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
12191 DCHECK(!bar_func_.is_null());
12194 i::Handle<i::JSFunction>::cast(
12195 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
12196 DCHECK(!foo_func_.is_null());
12198 v8::Handle<v8::Value> value = CompileRun("bar();");
12199 CHECK(value->IsNumber());
12200 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12202 // Test the optimized codegen path.
12203 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
12205 CHECK(value->IsNumber());
12206 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12212 void SetFunctionEntryHookTest::RunTest() {
12213 // Work in a new isolate throughout.
12214 v8::Isolate::CreateParams create_params;
12215 create_params.entry_hook = EntryHook;
12216 create_params.code_event_handler = JitEvent;
12217 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
12218 v8::Isolate* isolate = v8::Isolate::New(create_params);
12221 v8::Isolate::Scope scope(isolate);
12223 RunLoopInNewEnv(isolate);
12225 // Check the exepected invocation counts.
12226 CHECK_EQ(2, CountInvocations(NULL, "bar"));
12227 CHECK_EQ(200, CountInvocations("bar", "foo"));
12228 CHECK_EQ(200, CountInvocations(NULL, "foo"));
12230 // Verify that we have an entry hook on some specific stubs.
12231 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
12232 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
12233 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
12235 isolate->Dispose();
12239 // Make sure a second isolate is unaffected by the previous entry hook.
12240 create_params = v8::Isolate::CreateParams();
12241 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
12242 isolate = v8::Isolate::New(create_params);
12244 v8::Isolate::Scope scope(isolate);
12246 // Reset the entry count to zero and set the entry hook.
12247 RunLoopInNewEnv(isolate);
12249 // We should record no invocations in this isolate.
12250 CHECK_EQ(0, static_cast<int>(invocations_.size()));
12253 isolate->Dispose();
12257 TEST(SetFunctionEntryHook) {
12258 // FunctionEntryHook does not work well with experimental natives.
12259 // Experimental natives are compiled during snapshot deserialization.
12260 // This test breaks because InstallGetter (function from snapshot that
12261 // only gets called from experimental natives) is compiled with entry hooks.
12262 i::FLAG_allow_natives_syntax = true;
12263 i::FLAG_use_inlining = false;
12265 SetFunctionEntryHookTest test;
12270 static i::HashMap* code_map = NULL;
12271 static i::HashMap* jitcode_line_info = NULL;
12272 static int saw_bar = 0;
12273 static int move_events = 0;
12276 static bool FunctionNameIs(const char* expected,
12277 const v8::JitCodeEvent* event) {
12278 // Log lines for functions are of the general form:
12279 // "LazyCompile:<type><function_name>", where the type is one of
12281 static const char kPreamble[] = "LazyCompile:";
12282 static size_t kPreambleLen = sizeof(kPreamble) - 1;
12284 if (event->name.len < sizeof(kPreamble) - 1 ||
12285 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
12289 const char* tail = event->name.str + kPreambleLen;
12290 size_t tail_len = event->name.len - kPreambleLen;
12291 size_t expected_len = strlen(expected);
12292 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
12297 // Check for tails like 'bar :1'.
12298 if (tail_len > expected_len + 2 &&
12299 tail[expected_len] == ' ' &&
12300 tail[expected_len + 1] == ':' &&
12301 tail[expected_len + 2] &&
12302 !strncmp(tail, expected, expected_len)) {
12306 if (tail_len != expected_len)
12309 return strncmp(tail, expected, expected_len) == 0;
12313 static void event_handler(const v8::JitCodeEvent* event) {
12314 CHECK(event != NULL);
12315 CHECK(code_map != NULL);
12316 CHECK(jitcode_line_info != NULL);
12318 class DummyJitCodeLineInfo {
12321 switch (event->type) {
12322 case v8::JitCodeEvent::CODE_ADDED: {
12323 CHECK(event->code_start != NULL);
12324 CHECK_NE(0, static_cast<int>(event->code_len));
12325 CHECK(event->name.str != NULL);
12326 i::HashMap::Entry* entry = code_map->LookupOrInsert(
12327 event->code_start, i::ComputePointerHash(event->code_start));
12328 entry->value = reinterpret_cast<void*>(event->code_len);
12330 if (FunctionNameIs("bar", event)) {
12336 case v8::JitCodeEvent::CODE_MOVED: {
12337 uint32_t hash = i::ComputePointerHash(event->code_start);
12338 // We would like to never see code move that we haven't seen before,
12339 // but the code creation event does not happen until the line endings
12340 // have been calculated (this is so that we can report the line in the
12341 // script at which the function source is found, see
12342 // Compiler::RecordFunctionCompilation) and the line endings
12343 // calculations can cause a GC, which can move the newly created code
12344 // before its existence can be logged.
12345 i::HashMap::Entry* entry = code_map->Lookup(event->code_start, hash);
12346 if (entry != NULL) {
12349 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
12350 code_map->Remove(event->code_start, hash);
12352 entry = code_map->LookupOrInsert(
12353 event->new_code_start,
12354 i::ComputePointerHash(event->new_code_start));
12355 entry->value = reinterpret_cast<void*>(event->code_len);
12360 case v8::JitCodeEvent::CODE_REMOVED:
12361 // Object/code removal events are currently not dispatched from the GC.
12365 // For CODE_START_LINE_INFO_RECORDING event, we will create one
12366 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
12367 // record it in jitcode_line_info.
12368 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
12369 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
12370 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
12371 temp_event->user_data = line_info;
12372 i::HashMap::Entry* entry = jitcode_line_info->LookupOrInsert(
12373 line_info, i::ComputePointerHash(line_info));
12374 entry->value = reinterpret_cast<void*>(line_info);
12377 // For these two events, we will check whether the event->user_data
12378 // data structure is created before during CODE_START_LINE_INFO_RECORDING
12379 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
12380 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
12381 CHECK(event->user_data != NULL);
12382 uint32_t hash = i::ComputePointerHash(event->user_data);
12383 i::HashMap::Entry* entry =
12384 jitcode_line_info->Lookup(event->user_data, hash);
12385 CHECK(entry != NULL);
12386 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
12390 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
12391 CHECK(event->user_data != NULL);
12392 uint32_t hash = i::ComputePointerHash(event->user_data);
12393 i::HashMap::Entry* entry =
12394 jitcode_line_info->Lookup(event->user_data, hash);
12395 CHECK(entry != NULL);
12400 // Impossible event.
12407 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
12408 i::FLAG_stress_compaction = true;
12409 i::FLAG_incremental_marking = false;
12410 if (i::FLAG_never_compact) return;
12411 const char* script =
12414 " for (i = 0; i < 10; ++i)"
12418 "function foo(i) { return i; };"
12421 // Run this test in a new isolate to make sure we don't
12422 // have remnants of state from other code.
12423 v8::Isolate::CreateParams create_params;
12424 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
12425 v8::Isolate* isolate = v8::Isolate::New(create_params);
12427 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
12428 i::Heap* heap = i_isolate->heap();
12430 // Start with a clean slate.
12431 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Prepare");
12434 v8::HandleScope scope(isolate);
12435 i::HashMap code(MatchPointers);
12438 i::HashMap lineinfo(MatchPointers);
12439 jitcode_line_info = &lineinfo;
12444 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
12446 // Generate new code objects sparsely distributed across several
12447 // different fragmented code-space pages.
12448 const int kIterations = 10;
12449 for (int i = 0; i < kIterations; ++i) {
12450 LocalContext env(isolate);
12451 i::AlwaysAllocateScope always_allocate(i_isolate);
12452 SimulateFullSpace(heap->code_space());
12453 CompileRun(script);
12455 // Keep a strong reference to the code object in the handle scope.
12456 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
12457 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
12458 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
12459 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
12461 // Clear the compilation cache to get more wastage.
12462 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
12465 // Force code movement.
12466 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Move");
12468 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
12470 CHECK_LE(kIterations, saw_bar);
12471 CHECK_LT(0, move_events);
12474 jitcode_line_info = NULL;
12478 isolate->Dispose();
12480 // Do this in a new isolate.
12481 isolate = v8::Isolate::New(create_params);
12484 // Verify that we get callbacks for existing code objects when we
12485 // request enumeration of existing code.
12487 v8::HandleScope scope(isolate);
12488 LocalContext env(isolate);
12489 CompileRun(script);
12491 // Now get code through initial iteration.
12492 i::HashMap code(MatchPointers);
12495 i::HashMap lineinfo(MatchPointers);
12496 jitcode_line_info = &lineinfo;
12498 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
12500 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
12502 jitcode_line_info = NULL;
12503 // We expect that we got some events. Note that if we could get code removal
12504 // notifications, we could compare two collections, one created by listening
12505 // from the time of creation of an isolate, and the other by subscribing
12506 // with EnumExisting.
12507 CHECK_LT(0u, code.occupancy());
12513 isolate->Dispose();
12517 THREADED_TEST(ExternalAllocatedMemory) {
12518 v8::Isolate* isolate = CcTest::isolate();
12519 v8::HandleScope outer(isolate);
12520 v8::Local<Context> env(Context::New(isolate));
12521 CHECK(!env.IsEmpty());
12522 const int64_t kSize = 1024*1024;
12523 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
12524 CHECK_EQ(baseline + kSize,
12525 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
12527 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
12528 const int64_t kTriggerGCSize =
12529 v8::internal::Internals::kExternalAllocationLimit + 1;
12530 CHECK_EQ(baseline + kTriggerGCSize,
12531 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
12533 isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
12537 // Regression test for issue 54, object templates with internal fields
12538 // but no accessors or interceptors did not get their internal field
12539 // count set on instances.
12540 THREADED_TEST(Regress54) {
12541 LocalContext context;
12542 v8::Isolate* isolate = context->GetIsolate();
12543 v8::HandleScope outer(isolate);
12544 static v8::Persistent<v8::ObjectTemplate> templ;
12545 if (templ.IsEmpty()) {
12546 v8::EscapableHandleScope inner(isolate);
12547 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
12548 local->SetInternalFieldCount(1);
12549 templ.Reset(isolate, inner.Escape(local));
12551 v8::Handle<v8::Object> result =
12552 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
12553 CHECK_EQ(1, result->InternalFieldCount());
12557 // If part of the threaded tests, this test makes ThreadingTest fail
12559 TEST(CatchStackOverflow) {
12560 LocalContext context;
12561 v8::HandleScope scope(context->GetIsolate());
12562 v8::TryCatch try_catch(context->GetIsolate());
12563 v8::Handle<v8::Value> result = CompileRun(
12569 CHECK(result.IsEmpty());
12573 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
12574 const char* resource_name,
12576 v8::HandleScope scope(CcTest::isolate());
12577 v8::TryCatch try_catch(CcTest::isolate());
12578 v8::Handle<v8::Value> result = script->Run();
12579 CHECK(result.IsEmpty());
12580 CHECK(try_catch.HasCaught());
12581 v8::Handle<v8::Message> message = try_catch.Message();
12582 CHECK(!message.IsEmpty());
12583 CHECK_EQ(10 + line_offset, message->GetLineNumber());
12584 CHECK_EQ(91, message->GetStartPosition());
12585 CHECK_EQ(92, message->GetEndPosition());
12586 CHECK_EQ(2, message->GetStartColumn());
12587 CHECK_EQ(3, message->GetEndColumn());
12588 v8::String::Utf8Value line(message->GetSourceLine());
12589 CHECK_EQ(0, strcmp(" throw 'nirk';", *line));
12590 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
12591 CHECK_EQ(0, strcmp(resource_name, *name));
12595 THREADED_TEST(TryCatchSourceInfo) {
12596 LocalContext context;
12597 v8::HandleScope scope(context->GetIsolate());
12598 v8::Local<v8::String> source = v8_str(
12599 "function Foo() {\n"
12603 "function Bar() {\n"
12607 "function Baz() {\n"
12613 const char* resource_name;
12614 v8::Handle<v8::Script> script;
12615 resource_name = "test.js";
12616 script = CompileWithOrigin(source, resource_name);
12617 CheckTryCatchSourceInfo(script, resource_name, 0);
12619 resource_name = "test1.js";
12620 v8::ScriptOrigin origin1(
12621 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
12622 script = v8::Script::Compile(source, &origin1);
12623 CheckTryCatchSourceInfo(script, resource_name, 0);
12625 resource_name = "test2.js";
12626 v8::ScriptOrigin origin2(
12627 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
12628 v8::Integer::New(context->GetIsolate(), 7));
12629 script = v8::Script::Compile(source, &origin2);
12630 CheckTryCatchSourceInfo(script, resource_name, 7);
12634 THREADED_TEST(TryCatchSourceInfoForEOSError) {
12635 LocalContext context;
12636 v8::HandleScope scope(context->GetIsolate());
12637 v8::TryCatch try_catch(context->GetIsolate());
12638 v8::Script::Compile(v8_str("!\n"));
12639 CHECK(try_catch.HasCaught());
12640 v8::Handle<v8::Message> message = try_catch.Message();
12641 CHECK_EQ(1, message->GetLineNumber());
12642 CHECK_EQ(0, message->GetStartColumn());
12646 THREADED_TEST(CompilationCache) {
12647 LocalContext context;
12648 v8::HandleScope scope(context->GetIsolate());
12649 v8::Handle<v8::String> source0 =
12650 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
12651 v8::Handle<v8::String> source1 =
12652 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
12653 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
12654 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
12655 v8::Handle<v8::Script> script2 =
12656 v8::Script::Compile(source0); // different origin
12657 CHECK_EQ(1234, script0->Run()->Int32Value());
12658 CHECK_EQ(1234, script1->Run()->Int32Value());
12659 CHECK_EQ(1234, script2->Run()->Int32Value());
12663 static void FunctionNameCallback(
12664 const v8::FunctionCallbackInfo<v8::Value>& args) {
12665 ApiTestFuzzer::Fuzz();
12666 args.GetReturnValue().Set(v8_num(42));
12670 THREADED_TEST(CallbackFunctionName) {
12671 LocalContext context;
12672 v8::Isolate* isolate = context->GetIsolate();
12673 v8::HandleScope scope(isolate);
12674 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
12675 t->Set(v8_str("asdf"),
12676 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
12677 context->Global()->Set(v8_str("obj"), t->NewInstance());
12678 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
12679 CHECK(value->IsString());
12680 v8::String::Utf8Value name(value);
12681 CHECK_EQ(0, strcmp("asdf", *name));
12685 THREADED_TEST(DateAccess) {
12686 LocalContext context;
12687 v8::HandleScope scope(context->GetIsolate());
12688 v8::Handle<v8::Value> date =
12689 v8::Date::New(context->GetIsolate(), 1224744689038.0);
12690 CHECK(date->IsDate());
12691 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
12695 void CheckProperties(v8::Isolate* isolate, v8::Handle<v8::Value> val,
12696 unsigned elmc, const char* elmv[]) {
12697 v8::Handle<v8::Object> obj = val.As<v8::Object>();
12698 v8::Handle<v8::Array> props = obj->GetPropertyNames();
12699 CHECK_EQ(elmc, props->Length());
12700 for (unsigned i = 0; i < elmc; i++) {
12701 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
12702 CHECK_EQ(0, strcmp(elmv[i], *elm));
12707 void CheckOwnProperties(v8::Isolate* isolate, v8::Handle<v8::Value> val,
12708 unsigned elmc, const char* elmv[]) {
12709 v8::Handle<v8::Object> obj = val.As<v8::Object>();
12710 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
12711 CHECK_EQ(elmc, props->Length());
12712 for (unsigned i = 0; i < elmc; i++) {
12713 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
12714 CHECK_EQ(0, strcmp(elmv[i], *elm));
12719 THREADED_TEST(PropertyEnumeration) {
12720 LocalContext context;
12721 v8::Isolate* isolate = context->GetIsolate();
12722 v8::HandleScope scope(isolate);
12723 v8::Handle<v8::Value> obj = CompileRun(
12726 "result[1] = {a: 1, b: 2};"
12727 "result[2] = [1, 2, 3];"
12728 "var proto = {x: 1, y: 2, z: 3};"
12729 "var x = { __proto__: proto, w: 0, z: 1 };"
12732 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12733 CHECK_EQ(4u, elms->Length());
12735 const char** elmv0 = NULL;
12737 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12738 CheckOwnProperties(
12739 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12741 const char* elmv1[] = {"a", "b"};
12743 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
12744 CheckOwnProperties(
12745 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
12747 const char* elmv2[] = {"0", "1", "2"};
12749 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
12750 CheckOwnProperties(
12751 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
12753 const char* elmv3[] = {"w", "z", "x", "y"};
12755 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
12757 const char* elmv4[] = {"w", "z"};
12758 CheckOwnProperties(
12759 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
12763 THREADED_TEST(PropertyEnumeration2) {
12764 LocalContext context;
12765 v8::Isolate* isolate = context->GetIsolate();
12766 v8::HandleScope scope(isolate);
12767 v8::Handle<v8::Value> obj = CompileRun(
12770 "result[1] = {a: 1, b: 2};"
12771 "result[2] = [1, 2, 3];"
12772 "var proto = {x: 1, y: 2, z: 3};"
12773 "var x = { __proto__: proto, w: 0, z: 1 };"
12776 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12777 CHECK_EQ(4u, elms->Length());
12779 const char** elmv0 = NULL;
12780 CheckProperties(isolate,
12781 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12783 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
12784 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
12785 CHECK_EQ(0u, props->Length());
12786 for (uint32_t i = 0; i < props->Length(); i++) {
12787 printf("p[%u]\n", i);
12792 THREADED_TEST(AccessChecksReenabledCorrectly) {
12793 LocalContext context;
12794 v8::Isolate* isolate = context->GetIsolate();
12795 v8::HandleScope scope(isolate);
12796 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
12797 templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
12798 templ->Set(v8_str("a"), v8_str("a"));
12799 // Add more than 8 (see kMaxFastProperties) properties
12800 // so that the constructor will force copying map.
12801 // Cannot sprintf, gcc complains unsafety.
12803 for (char i = '0'; i <= '9' ; i++) {
12805 for (char j = '0'; j <= '9'; j++) {
12807 for (char k = '0'; k <= '9'; k++) {
12810 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
12815 Local<v8::Object> instance_1 = templ->NewInstance();
12816 context->Global()->Set(v8_str("obj_1"), instance_1);
12818 Local<Value> value_1 = CompileRun("obj_1.a");
12819 CHECK(value_1.IsEmpty());
12821 Local<v8::Object> instance_2 = templ->NewInstance();
12822 context->Global()->Set(v8_str("obj_2"), instance_2);
12824 Local<Value> value_2 = CompileRun("obj_2.a");
12825 CHECK(value_2.IsEmpty());
12829 // Tests that ScriptData can be serialized and deserialized.
12830 TEST(PreCompileSerialization) {
12831 v8::V8::Initialize();
12833 v8::Isolate* isolate = env->GetIsolate();
12834 HandleScope handle_scope(isolate);
12836 i::FLAG_min_preparse_length = 0;
12837 const char* script = "function foo(a) { return a+1; }";
12838 v8::ScriptCompiler::Source source(v8_str(script));
12839 v8::ScriptCompiler::Compile(isolate, &source,
12840 v8::ScriptCompiler::kProduceParserCache);
12842 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
12843 i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
12844 i::MemCopy(serialized_data, cd->data, cd->length);
12847 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
12849 // Verify that the original is the same as the deserialized.
12850 CHECK_EQ(cd->length, deserialized->length());
12851 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
12853 delete deserialized;
12854 i::DeleteArray(serialized_data);
12858 // This tests that we do not allow dictionary load/call inline caches
12859 // to use functions that have not yet been compiled. The potential
12860 // problem of loading a function that has not yet been compiled can
12861 // arise because we share code between contexts via the compilation
12863 THREADED_TEST(DictionaryICLoadedFunction) {
12864 v8::HandleScope scope(CcTest::isolate());
12866 for (int i = 0; i < 2; i++) {
12867 LocalContext context;
12868 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
12869 context->Global()->Delete(v8_str("tmp"));
12870 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12873 for (int i = 0; i < 2; i++) {
12874 LocalContext context;
12875 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
12876 context->Global()->Delete(v8_str("tmp"));
12877 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12882 // Test that cross-context new calls use the context of the callee to
12883 // create the new JavaScript object.
12884 THREADED_TEST(CrossContextNew) {
12885 v8::Isolate* isolate = CcTest::isolate();
12886 v8::HandleScope scope(isolate);
12887 v8::Local<Context> context0 = Context::New(isolate);
12888 v8::Local<Context> context1 = Context::New(isolate);
12890 // Allow cross-domain access.
12891 Local<String> token = v8_str("<security token>");
12892 context0->SetSecurityToken(token);
12893 context1->SetSecurityToken(token);
12895 // Set an 'x' property on the Object prototype and define a
12896 // constructor function in context0.
12898 CompileRun("Object.prototype.x = 42; function C() {};");
12901 // Call the constructor function from context0 and check that the
12902 // result has the 'x' property.
12904 context1->Global()->Set(v8_str("other"), context0->Global());
12905 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12906 CHECK(value->IsInt32());
12907 CHECK_EQ(42, value->Int32Value());
12912 // Verify that we can clone an object
12913 TEST(ObjectClone) {
12915 v8::Isolate* isolate = env->GetIsolate();
12916 v8::HandleScope scope(isolate);
12918 const char* sample =
12920 "rv.alpha = 'hello';" \
12924 // Create an object, verify basics.
12925 Local<Value> val = CompileRun(sample);
12926 CHECK(val->IsObject());
12927 Local<v8::Object> obj = val.As<v8::Object>();
12928 obj->Set(v8_str("gamma"), v8_str("cloneme"));
12930 CHECK(v8_str("hello")->Equals(obj->Get(v8_str("alpha"))));
12931 CHECK(v8::Integer::New(isolate, 123)->Equals(obj->Get(v8_str("beta"))));
12932 CHECK(v8_str("cloneme")->Equals(obj->Get(v8_str("gamma"))));
12935 Local<v8::Object> clone = obj->Clone();
12936 CHECK(v8_str("hello")->Equals(clone->Get(v8_str("alpha"))));
12937 CHECK(v8::Integer::New(isolate, 123)->Equals(clone->Get(v8_str("beta"))));
12938 CHECK(v8_str("cloneme")->Equals(clone->Get(v8_str("gamma"))));
12940 // Set a property on the clone, verify each object.
12941 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
12942 CHECK(v8::Integer::New(isolate, 123)->Equals(obj->Get(v8_str("beta"))));
12943 CHECK(v8::Integer::New(isolate, 456)->Equals(clone->Get(v8_str("beta"))));
12947 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
12949 explicit OneByteVectorResource(i::Vector<const char> vector)
12951 virtual ~OneByteVectorResource() {}
12952 virtual size_t length() const { return data_.length(); }
12953 virtual const char* data() const { return data_.start(); }
12955 i::Vector<const char> data_;
12959 class UC16VectorResource : public v8::String::ExternalStringResource {
12961 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
12963 virtual ~UC16VectorResource() {}
12964 virtual size_t length() const { return data_.length(); }
12965 virtual const i::uc16* data() const { return data_.start(); }
12967 i::Vector<const i::uc16> data_;
12971 static void MorphAString(i::String* string,
12972 OneByteVectorResource* one_byte_resource,
12973 UC16VectorResource* uc16_resource) {
12974 CHECK(i::StringShape(string).IsExternal());
12975 if (string->IsOneByteRepresentation()) {
12976 // Check old map is not internalized or long.
12977 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
12978 // Morph external string to be TwoByte string.
12979 string->set_map(CcTest::heap()->external_string_map());
12980 i::ExternalTwoByteString* morphed =
12981 i::ExternalTwoByteString::cast(string);
12982 morphed->set_resource(uc16_resource);
12984 // Check old map is not internalized or long.
12985 CHECK(string->map() == CcTest::heap()->external_string_map());
12986 // Morph external string to be one-byte string.
12987 string->set_map(CcTest::heap()->external_one_byte_string_map());
12988 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
12989 morphed->set_resource(one_byte_resource);
12994 // Test that we can still flatten a string if the components it is built up
12995 // from have been turned into 16 bit strings in the mean time.
12996 THREADED_TEST(MorphCompositeStringTest) {
12997 char utf_buffer[129];
12998 const char* c_string = "Now is the time for all good men"
12999 " to come to the aid of the party";
13000 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
13003 i::Factory* factory = CcTest::i_isolate()->factory();
13004 v8::HandleScope scope(env->GetIsolate());
13005 OneByteVectorResource one_byte_resource(
13006 i::Vector<const char>(c_string, i::StrLength(c_string)));
13007 UC16VectorResource uc16_resource(
13008 i::Vector<const uint16_t>(two_byte_string,
13009 i::StrLength(c_string)));
13012 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
13013 &one_byte_resource).ToHandleChecked()));
13015 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
13016 &one_byte_resource).ToHandleChecked()));
13018 env->Global()->Set(v8_str("lhs"), lhs);
13019 env->Global()->Set(v8_str("rhs"), rhs);
13022 "var cons = lhs + rhs;"
13023 "var slice = lhs.substring(1, lhs.length - 1);"
13024 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
13026 CHECK(lhs->IsOneByte());
13027 CHECK(rhs->IsOneByte());
13029 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
13031 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
13034 // This should UTF-8 without flattening, since everything is ASCII.
13035 Handle<String> cons = v8_compile("cons")->Run().As<String>();
13036 CHECK_EQ(128, cons->Utf8Length());
13038 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
13039 CHECK_EQ(128, nchars);
13040 CHECK_EQ(0, strcmp(
13042 "Now is the time for all good men to come to the aid of the party"
13043 "Now is the time for all good men to come to the aid of the party"));
13045 // Now do some stuff to make sure the strings are flattened, etc.
13047 "/[^a-z]/.test(cons);"
13048 "/[^a-z]/.test(slice);"
13049 "/[^a-z]/.test(slice_on_cons);");
13050 const char* expected_cons =
13051 "Now is the time for all good men to come to the aid of the party"
13052 "Now is the time for all good men to come to the aid of the party";
13053 const char* expected_slice =
13054 "ow is the time for all good men to come to the aid of the part";
13055 const char* expected_slice_on_cons =
13056 "ow is the time for all good men to come to the aid of the party"
13057 "Now is the time for all good men to come to the aid of the part";
13058 CHECK(String::NewFromUtf8(env->GetIsolate(), expected_cons)
13059 ->Equals(env->Global()->Get(v8_str("cons"))));
13060 CHECK(String::NewFromUtf8(env->GetIsolate(), expected_slice)
13061 ->Equals(env->Global()->Get(v8_str("slice"))));
13062 CHECK(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons)
13063 ->Equals(env->Global()->Get(v8_str("slice_on_cons"))));
13065 i::DeleteArray(two_byte_string);
13069 TEST(CompileExternalTwoByteSource) {
13070 LocalContext context;
13071 v8::HandleScope scope(context->GetIsolate());
13073 // This is a very short list of sources, which currently is to check for a
13074 // regression caused by r2703.
13075 const char* one_byte_sources[] = {
13077 "-0.5", // This mainly testes PushBack in the Scanner.
13078 "--0.5", // This mainly testes PushBack in the Scanner.
13081 // Compile the sources as external two byte strings.
13082 for (int i = 0; one_byte_sources[i] != NULL; i++) {
13083 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
13084 TestResource* uc16_resource = new TestResource(two_byte_string);
13085 v8::Local<v8::String> source =
13086 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
13087 v8::Script::Compile(source);
13092 #ifndef V8_INTERPRETED_REGEXP
13094 struct RegExpInterruptionData {
13095 v8::base::Atomic32 loop_count;
13096 UC16VectorResource* string_resource;
13097 v8::Persistent<v8::String> string;
13098 } regexp_interruption_data;
13101 class RegExpInterruptionThread : public v8::base::Thread {
13103 explicit RegExpInterruptionThread(v8::Isolate* isolate)
13104 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
13106 virtual void Run() {
13107 for (v8::base::NoBarrier_Store(®exp_interruption_data.loop_count, 0);
13108 v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) < 7;
13109 v8::base::NoBarrier_AtomicIncrement(
13110 ®exp_interruption_data.loop_count, 1)) {
13111 // Wait a bit before requesting GC.
13112 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
13113 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
13115 // Wait a bit before terminating.
13116 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(50));
13117 v8::V8::TerminateExecution(isolate_);
13121 v8::Isolate* isolate_;
13125 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
13126 if (v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) != 2) {
13129 v8::HandleScope scope(CcTest::isolate());
13130 v8::Local<v8::String> string = v8::Local<v8::String>::New(
13131 CcTest::isolate(), regexp_interruption_data.string);
13132 string->MakeExternal(regexp_interruption_data.string_resource);
13136 // Test that RegExp execution can be interrupted. Specifically, we test
13137 // * interrupting with GC
13138 // * turn the subject string from one-byte internal to two-byte external string
13139 // * force termination
13140 TEST(RegExpInterruption) {
13141 v8::HandleScope scope(CcTest::isolate());
13144 RegExpInterruptionThread timeout_thread(CcTest::isolate());
13146 v8::V8::AddGCPrologueCallback(RunBeforeGC);
13147 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
13148 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
13149 v8::Local<v8::String> string = v8_str(one_byte_content);
13151 CcTest::global()->Set(v8_str("a"), string);
13152 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
13153 regexp_interruption_data.string_resource = new UC16VectorResource(
13154 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
13156 v8::TryCatch try_catch(CcTest::isolate());
13157 timeout_thread.Start();
13159 CompileRun("/((a*)*)*b/.exec(a)");
13160 CHECK(try_catch.HasTerminated());
13162 timeout_thread.Join();
13164 regexp_interruption_data.string.Reset();
13165 i::DeleteArray(uc16_content);
13168 #endif // V8_INTERPRETED_REGEXP
13171 // Test that we cannot set a property on the global object if there
13172 // is a read-only property in the prototype chain.
13173 TEST(ReadOnlyPropertyInGlobalProto) {
13174 v8::Isolate* isolate = CcTest::isolate();
13175 v8::HandleScope scope(isolate);
13176 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13177 LocalContext context(0, templ);
13178 v8::Handle<v8::Object> global = context->Global();
13179 v8::Handle<v8::Object> global_proto =
13180 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
13181 global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
13183 global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
13185 // Check without 'eval' or 'with'.
13186 v8::Handle<v8::Value> res =
13187 CompileRun("function f() { x = 42; return x; }; f()");
13188 CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13189 // Check with 'eval'.
13190 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
13191 CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13192 // Check with 'with'.
13193 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
13194 CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13197 static int force_set_set_count = 0;
13198 static int force_set_get_count = 0;
13199 bool pass_on_get = false;
13201 static void ForceSetGetter(v8::Local<v8::String> name,
13202 const v8::PropertyCallbackInfo<v8::Value>& info) {
13203 force_set_get_count++;
13207 info.GetReturnValue().Set(3);
13210 static void ForceSetSetter(v8::Local<v8::String> name,
13211 v8::Local<v8::Value> value,
13212 const v8::PropertyCallbackInfo<void>& info) {
13213 force_set_set_count++;
13216 static void ForceSetInterceptGetter(
13217 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13218 CHECK(name->IsString());
13219 ForceSetGetter(Local<String>::Cast(name), info);
13222 static void ForceSetInterceptSetter(
13223 v8::Local<v8::Name> name, v8::Local<v8::Value> value,
13224 const v8::PropertyCallbackInfo<v8::Value>& info) {
13225 force_set_set_count++;
13226 info.GetReturnValue().SetUndefined();
13231 force_set_get_count = 0;
13232 force_set_set_count = 0;
13233 pass_on_get = false;
13235 v8::Isolate* isolate = CcTest::isolate();
13236 v8::HandleScope scope(isolate);
13237 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13238 v8::Handle<v8::String> access_property =
13239 v8::String::NewFromUtf8(isolate, "a");
13240 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
13241 LocalContext context(NULL, templ);
13242 v8::Handle<v8::Object> global = context->Global();
13244 // Ordinary properties
13245 v8::Handle<v8::String> simple_property =
13246 v8::String::NewFromUtf8(isolate, "p");
13247 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
13248 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13249 // This should fail because the property is read-only
13250 global->Set(simple_property, v8::Int32::New(isolate, 5));
13251 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13252 // This should succeed even though the property is read-only
13253 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
13254 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
13257 CHECK_EQ(0, force_set_set_count);
13258 CHECK_EQ(0, force_set_get_count);
13259 CHECK_EQ(3, global->Get(access_property)->Int32Value());
13260 // CHECK_EQ the property shouldn't override it, just call the setter
13261 // which in this case does nothing.
13262 global->Set(access_property, v8::Int32::New(isolate, 7));
13263 CHECK_EQ(3, global->Get(access_property)->Int32Value());
13264 CHECK_EQ(1, force_set_set_count);
13265 CHECK_EQ(2, force_set_get_count);
13266 // ForceSet doesn't call the accessors for now.
13267 // TODO(verwaest): Update once blink doesn't rely on ForceSet to delete api
13269 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
13270 CHECK_EQ(8, global->Get(access_property)->Int32Value());
13271 CHECK_EQ(1, force_set_set_count);
13272 CHECK_EQ(2, force_set_get_count);
13276 TEST(ForceSetWithInterceptor) {
13277 v8::Isolate* isolate = CcTest::isolate();
13278 v8::HandleScope scope(isolate);
13279 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13280 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13281 ForceSetInterceptGetter, ForceSetInterceptSetter));
13282 pass_on_get = true;
13283 LocalContext context(NULL, templ);
13284 v8::Handle<v8::Object> global = context->Global();
13286 force_set_get_count = 0;
13287 force_set_set_count = 0;
13288 pass_on_get = false;
13290 v8::Handle<v8::String> some_property =
13291 v8::String::NewFromUtf8(isolate, "a");
13292 CHECK_EQ(0, force_set_set_count);
13293 CHECK_EQ(0, force_set_get_count);
13294 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13295 // Setting the property shouldn't override it, just call the setter
13296 // which in this case does nothing.
13297 global->Set(some_property, v8::Int32::New(isolate, 7));
13298 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13299 CHECK_EQ(1, force_set_set_count);
13300 CHECK_EQ(2, force_set_get_count);
13301 // Getting the property when the interceptor returns an empty handle
13302 // should yield undefined, since the property isn't present on the
13303 // object itself yet.
13304 pass_on_get = true;
13305 CHECK(global->Get(some_property)->IsUndefined());
13306 CHECK_EQ(1, force_set_set_count);
13307 CHECK_EQ(3, force_set_get_count);
13308 // Forcing the property to be set should cause the value to be
13309 // set locally without calling the interceptor.
13310 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
13311 CHECK_EQ(8, global->Get(some_property)->Int32Value());
13312 CHECK_EQ(1, force_set_set_count);
13313 CHECK_EQ(4, force_set_get_count);
13314 // Reenabling the interceptor should cause it to take precedence over
13316 pass_on_get = false;
13317 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13318 CHECK_EQ(1, force_set_set_count);
13319 CHECK_EQ(5, force_set_get_count);
13320 // The interceptor should also work for other properties
13321 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
13323 CHECK_EQ(1, force_set_set_count);
13324 CHECK_EQ(6, force_set_get_count);
13328 TEST(CreateDataProperty) {
13330 v8::Isolate* isolate = env->GetIsolate();
13331 v8::HandleScope handle_scope(isolate);
13336 "Object.defineProperty(a, 'foo', {value: 23});"
13337 "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
13339 v8::Local<v8::Object> obj =
13340 v8::Local<v8::Object>::Cast(env->Global()->Get(v8_str("a")));
13341 v8::Local<v8::Array> arr =
13342 v8::Local<v8::Array>::Cast(env->Global()->Get(v8_str("b")));
13344 // Can't change a non-configurable properties.
13345 v8::TryCatch try_catch(isolate);
13346 CHECK(!obj->CreateDataProperty(env.local(), v8_str("foo"),
13347 v8::Integer::New(isolate, 42)).FromJust());
13348 CHECK(!try_catch.HasCaught());
13349 CHECK(obj->CreateDataProperty(env.local(), v8_str("bar"),
13350 v8::Integer::New(isolate, 42)).FromJust());
13351 CHECK(!try_catch.HasCaught());
13352 v8::Local<v8::Value> val =
13353 obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
13354 CHECK(val->IsNumber());
13355 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13359 // Set a regular property.
13360 v8::TryCatch try_catch(isolate);
13361 CHECK(obj->CreateDataProperty(env.local(), v8_str("blub"),
13362 v8::Integer::New(isolate, 42)).FromJust());
13363 CHECK(!try_catch.HasCaught());
13364 v8::Local<v8::Value> val =
13365 obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
13366 CHECK(val->IsNumber());
13367 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13371 // Set an indexed property.
13372 v8::TryCatch try_catch(isolate);
13373 CHECK(obj->CreateDataProperty(env.local(), v8_str("1"),
13374 v8::Integer::New(isolate, 42)).FromJust());
13375 CHECK(!try_catch.HasCaught());
13376 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
13377 CHECK(val->IsNumber());
13378 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13382 // Special cases for arrays.
13383 v8::TryCatch try_catch(isolate);
13384 CHECK(!arr->CreateDataProperty(env.local(), v8_str("length"),
13385 v8::Integer::New(isolate, 1)).FromJust());
13386 CHECK(!try_catch.HasCaught());
13389 // Special cases for arrays: index exceeds the array's length
13390 v8::TryCatch try_catch(isolate);
13391 CHECK(arr->CreateDataProperty(env.local(), 1, v8::Integer::New(isolate, 23))
13393 CHECK(!try_catch.HasCaught());
13394 CHECK_EQ(2U, arr->Length());
13395 v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
13396 CHECK(val->IsNumber());
13397 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
13399 // Set an existing entry.
13400 CHECK(arr->CreateDataProperty(env.local(), 0, v8::Integer::New(isolate, 42))
13402 CHECK(!try_catch.HasCaught());
13403 val = arr->Get(env.local(), 0).ToLocalChecked();
13404 CHECK(val->IsNumber());
13405 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13408 CompileRun("Object.freeze(a);");
13410 // Can't change non-extensible objects.
13411 v8::TryCatch try_catch(isolate);
13412 CHECK(!obj->CreateDataProperty(env.local(), v8_str("baz"),
13413 v8::Integer::New(isolate, 42)).FromJust());
13414 CHECK(!try_catch.HasCaught());
13417 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13418 templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
13419 v8::Local<v8::Object> access_checked =
13420 templ->NewInstance(env.local()).ToLocalChecked();
13422 v8::TryCatch try_catch(isolate);
13423 CHECK(access_checked->CreateDataProperty(env.local(), v8_str("foo"),
13424 v8::Integer::New(isolate, 42))
13426 CHECK(try_catch.HasCaught());
13431 TEST(DefineOwnProperty) {
13433 v8::Isolate* isolate = env->GetIsolate();
13434 v8::HandleScope handle_scope(isolate);
13439 "Object.defineProperty(a, 'foo', {value: 23});"
13440 "Object.defineProperty(a, 'bar', {value: 23, configurable: true});");
13442 v8::Local<v8::Object> obj =
13443 v8::Local<v8::Object>::Cast(env->Global()->Get(v8_str("a")));
13444 v8::Local<v8::Array> arr =
13445 v8::Local<v8::Array>::Cast(env->Global()->Get(v8_str("b")));
13447 // Can't change a non-configurable properties.
13448 v8::TryCatch try_catch(isolate);
13449 CHECK(!obj->DefineOwnProperty(env.local(), v8_str("foo"),
13450 v8::Integer::New(isolate, 42)).FromJust());
13451 CHECK(!try_catch.HasCaught());
13452 CHECK(obj->DefineOwnProperty(env.local(), v8_str("bar"),
13453 v8::Integer::New(isolate, 42)).FromJust());
13454 CHECK(!try_catch.HasCaught());
13455 v8::Local<v8::Value> val =
13456 obj->Get(env.local(), v8_str("bar")).ToLocalChecked();
13457 CHECK(val->IsNumber());
13458 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13462 // Set a regular property.
13463 v8::TryCatch try_catch(isolate);
13464 CHECK(obj->DefineOwnProperty(env.local(), v8_str("blub"),
13465 v8::Integer::New(isolate, 42)).FromJust());
13466 CHECK(!try_catch.HasCaught());
13467 v8::Local<v8::Value> val =
13468 obj->Get(env.local(), v8_str("blub")).ToLocalChecked();
13469 CHECK(val->IsNumber());
13470 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13474 // Set an indexed property.
13475 v8::TryCatch try_catch(isolate);
13476 CHECK(obj->DefineOwnProperty(env.local(), v8_str("1"),
13477 v8::Integer::New(isolate, 42)).FromJust());
13478 CHECK(!try_catch.HasCaught());
13479 v8::Local<v8::Value> val = obj->Get(env.local(), 1).ToLocalChecked();
13480 CHECK(val->IsNumber());
13481 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13485 // Special cases for arrays.
13486 v8::TryCatch try_catch(isolate);
13487 CHECK(!arr->DefineOwnProperty(env.local(), v8_str("length"),
13488 v8::Integer::New(isolate, 1)).FromJust());
13489 CHECK(!try_catch.HasCaught());
13492 // Special cases for arrays: index exceeds the array's length
13493 v8::TryCatch try_catch(isolate);
13494 CHECK(arr->DefineOwnProperty(env.local(), v8_str("1"),
13495 v8::Integer::New(isolate, 23)).FromJust());
13496 CHECK(!try_catch.HasCaught());
13497 CHECK_EQ(2U, arr->Length());
13498 v8::Local<v8::Value> val = arr->Get(env.local(), 1).ToLocalChecked();
13499 CHECK(val->IsNumber());
13500 CHECK_EQ(23.0, val->NumberValue(env.local()).FromJust());
13502 // Set an existing entry.
13503 CHECK(arr->DefineOwnProperty(env.local(), v8_str("0"),
13504 v8::Integer::New(isolate, 42)).FromJust());
13505 CHECK(!try_catch.HasCaught());
13506 val = arr->Get(env.local(), 0).ToLocalChecked();
13507 CHECK(val->IsNumber());
13508 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13512 // Set a non-writable property.
13513 v8::TryCatch try_catch(isolate);
13514 CHECK(obj->DefineOwnProperty(env.local(), v8_str("lala"),
13515 v8::Integer::New(isolate, 42),
13516 v8::ReadOnly).FromJust());
13517 CHECK(!try_catch.HasCaught());
13518 v8::Local<v8::Value> val =
13519 obj->Get(env.local(), v8_str("lala")).ToLocalChecked();
13520 CHECK(val->IsNumber());
13521 CHECK_EQ(42.0, val->NumberValue(env.local()).FromJust());
13522 CHECK_EQ(v8::ReadOnly, obj->GetPropertyAttributes(
13523 env.local(), v8_str("lala")).FromJust());
13524 CHECK(!try_catch.HasCaught());
13527 CompileRun("Object.freeze(a);");
13529 // Can't change non-extensible objects.
13530 v8::TryCatch try_catch(isolate);
13531 CHECK(!obj->DefineOwnProperty(env.local(), v8_str("baz"),
13532 v8::Integer::New(isolate, 42)).FromJust());
13533 CHECK(!try_catch.HasCaught());
13536 v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13537 templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
13538 v8::Local<v8::Object> access_checked =
13539 templ->NewInstance(env.local()).ToLocalChecked();
13541 v8::TryCatch try_catch(isolate);
13542 CHECK(access_checked->DefineOwnProperty(env.local(), v8_str("foo"),
13543 v8::Integer::New(isolate, 42))
13545 CHECK(try_catch.HasCaught());
13550 static v8::Local<Context> calling_context0;
13551 static v8::Local<Context> calling_context1;
13552 static v8::Local<Context> calling_context2;
13555 // Check that the call to the callback is initiated in
13556 // calling_context2, the directly calling context is calling_context1
13557 // and the callback itself is in calling_context0.
13558 static void GetCallingContextCallback(
13559 const v8::FunctionCallbackInfo<v8::Value>& args) {
13560 ApiTestFuzzer::Fuzz();
13561 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
13562 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
13563 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
13564 args.GetReturnValue().Set(42);
13568 THREADED_TEST(GetCurrentContextWhenNotInContext) {
13569 i::Isolate* isolate = CcTest::i_isolate();
13570 CHECK(isolate != NULL);
13571 CHECK(isolate->context() == NULL);
13572 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
13573 v8::HandleScope scope(v8_isolate);
13574 // The following should not crash, but return an empty handle.
13575 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
13576 CHECK(current.IsEmpty());
13580 THREADED_TEST(GetCallingContext) {
13581 v8::Isolate* isolate = CcTest::isolate();
13582 v8::HandleScope scope(isolate);
13584 Local<Context> calling_context0(Context::New(isolate));
13585 Local<Context> calling_context1(Context::New(isolate));
13586 Local<Context> calling_context2(Context::New(isolate));
13587 ::calling_context0 = calling_context0;
13588 ::calling_context1 = calling_context1;
13589 ::calling_context2 = calling_context2;
13591 // Allow cross-domain access.
13592 Local<String> token = v8_str("<security token>");
13593 calling_context0->SetSecurityToken(token);
13594 calling_context1->SetSecurityToken(token);
13595 calling_context2->SetSecurityToken(token);
13597 // Create an object with a C++ callback in context0.
13598 calling_context0->Enter();
13599 Local<v8::FunctionTemplate> callback_templ =
13600 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
13601 calling_context0->Global()->Set(v8_str("callback"),
13602 callback_templ->GetFunction());
13603 calling_context0->Exit();
13605 // Expose context0 in context1 and set up a function that calls the
13606 // callback function.
13607 calling_context1->Enter();
13608 calling_context1->Global()->Set(v8_str("context0"),
13609 calling_context0->Global());
13610 CompileRun("function f() { context0.callback() }");
13611 calling_context1->Exit();
13613 // Expose context1 in context2 and call the callback function in
13614 // context0 indirectly through f in context1.
13615 calling_context2->Enter();
13616 calling_context2->Global()->Set(v8_str("context1"),
13617 calling_context1->Global());
13618 CompileRun("context1.f()");
13619 calling_context2->Exit();
13620 ::calling_context0.Clear();
13621 ::calling_context1.Clear();
13622 ::calling_context2.Clear();
13626 // Check that a variable declaration with no explicit initialization
13627 // value does shadow an existing property in the prototype chain.
13628 THREADED_TEST(InitGlobalVarInProtoChain) {
13629 LocalContext context;
13630 v8::HandleScope scope(context->GetIsolate());
13631 // Introduce a variable in the prototype chain.
13632 CompileRun("__proto__.x = 42");
13633 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
13634 CHECK(!result->IsUndefined());
13635 CHECK_EQ(43, result->Int32Value());
13639 // Regression test for issue 398.
13640 // If a function is added to an object, creating a constant function
13641 // field, and the result is cloned, replacing the constant function on the
13642 // original should not affect the clone.
13643 // See http://code.google.com/p/v8/issues/detail?id=398
13644 THREADED_TEST(ReplaceConstantFunction) {
13645 LocalContext context;
13646 v8::Isolate* isolate = context->GetIsolate();
13647 v8::HandleScope scope(isolate);
13648 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
13649 v8::Handle<v8::FunctionTemplate> func_templ =
13650 v8::FunctionTemplate::New(isolate);
13651 v8::Handle<v8::String> foo_string =
13652 v8::String::NewFromUtf8(isolate, "foo");
13653 obj->Set(foo_string, func_templ->GetFunction());
13654 v8::Handle<v8::Object> obj_clone = obj->Clone();
13655 obj_clone->Set(foo_string,
13656 v8::String::NewFromUtf8(isolate, "Hello"));
13657 CHECK(!obj->Get(foo_string)->IsUndefined());
13661 static void CheckElementValue(i::Isolate* isolate,
13663 i::Handle<i::Object> obj,
13665 i::Object* element =
13666 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
13667 CHECK_EQ(expected, i::Smi::cast(element)->value());
13671 template <class ExternalArrayClass, class ElementType>
13672 static void ObjectWithExternalArrayTestHelper(Handle<Context> context,
13673 v8::Handle<Object> obj,
13675 i::ExternalArrayType array_type,
13676 int64_t low, int64_t high) {
13677 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13678 i::Isolate* isolate = jsobj->GetIsolate();
13679 obj->Set(v8_str("field"),
13680 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
13681 context->Global()->Set(v8_str("ext_array"), obj);
13682 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
13683 CHECK_EQ(1503, result->Int32Value());
13684 result = CompileRun("ext_array[1]");
13685 CHECK_EQ(1, result->Int32Value());
13687 // Check assigned smis
13688 result = CompileRun("for (var i = 0; i < 8; i++) {"
13689 " ext_array[i] = i;"
13692 "for (var i = 0; i < 8; i++) {"
13693 " sum += ext_array[i];"
13697 CHECK_EQ(28, result->Int32Value());
13698 // Check pass through of assigned smis
13699 result = CompileRun("var sum = 0;"
13700 "for (var i = 0; i < 8; i++) {"
13701 " sum += ext_array[i] = ext_array[i] = -i;"
13704 CHECK_EQ(-28, result->Int32Value());
13707 // Check assigned smis in reverse order
13708 result = CompileRun("for (var i = 8; --i >= 0; ) {"
13709 " ext_array[i] = i;"
13712 "for (var i = 0; i < 8; i++) {"
13713 " sum += ext_array[i];"
13716 CHECK_EQ(28, result->Int32Value());
13718 // Check pass through of assigned HeapNumbers
13719 result = CompileRun("var sum = 0;"
13720 "for (var i = 0; i < 16; i+=2) {"
13721 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
13724 CHECK_EQ(-28, result->Int32Value());
13726 // Check assigned HeapNumbers
13727 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
13728 " ext_array[i] = (i * 0.5);"
13731 "for (var i = 0; i < 16; i+=2) {"
13732 " sum += ext_array[i];"
13735 CHECK_EQ(28, result->Int32Value());
13737 // Check assigned HeapNumbers in reverse order
13738 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
13739 " ext_array[i] = (i * 0.5);"
13742 "for (var i = 0; i < 16; i+=2) {"
13743 " sum += ext_array[i];"
13746 CHECK_EQ(28, result->Int32Value());
13748 i::ScopedVector<char> test_buf(1024);
13750 // Check legal boundary conditions.
13751 // The repeated loads and stores ensure the ICs are exercised.
13752 const char* boundary_program =
13754 "for (var i = 0; i < 16; i++) {"
13755 " ext_array[i] = %lld;"
13757 " res = ext_array[i];"
13761 i::SNPrintF(test_buf,
13764 result = CompileRun(test_buf.start());
13765 CHECK_EQ(low, result->IntegerValue());
13767 i::SNPrintF(test_buf,
13770 result = CompileRun(test_buf.start());
13771 CHECK_EQ(high, result->IntegerValue());
13773 // Check misprediction of type in IC.
13774 result = CompileRun("var tmp_array = ext_array;"
13776 "for (var i = 0; i < 8; i++) {"
13777 " tmp_array[i] = i;"
13778 " sum += tmp_array[i];"
13784 // Force GC to trigger verification.
13785 CcTest::heap()->CollectAllGarbage();
13786 CHECK_EQ(28, result->Int32Value());
13788 // Make sure out-of-range loads do not throw.
13789 i::SNPrintF(test_buf,
13790 "var caught_exception = false;"
13794 " caught_exception = true;"
13796 "caught_exception;",
13798 result = CompileRun(test_buf.start());
13799 CHECK_EQ(false, result->BooleanValue());
13801 // Make sure out-of-range stores do not throw.
13802 i::SNPrintF(test_buf,
13803 "var caught_exception = false;"
13805 " ext_array[%d] = 1;"
13807 " caught_exception = true;"
13809 "caught_exception;",
13811 result = CompileRun(test_buf.start());
13812 CHECK_EQ(false, result->BooleanValue());
13814 // Check other boundary conditions, values and operations.
13815 result = CompileRun("for (var i = 0; i < 8; i++) {"
13816 " ext_array[7] = undefined;"
13819 CHECK_EQ(0, result->Int32Value());
13820 if (array_type == i::kExternalFloat64Array ||
13821 array_type == i::kExternalFloat32Array) {
13823 i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
13825 CheckElementValue(isolate, 0, jsobj, 7);
13828 result = CompileRun("for (var i = 0; i < 8; i++) {"
13829 " ext_array[6] = '2.3';"
13832 CHECK_EQ(2, result->Int32Value());
13835 i::Object::GetElement(
13836 isolate, jsobj, 6).ToHandleChecked()->Number()));
13838 if (array_type != i::kExternalFloat32Array &&
13839 array_type != i::kExternalFloat64Array) {
13840 // Though the specification doesn't state it, be explicit about
13841 // converting NaNs and +/-Infinity to zero.
13842 result = CompileRun("for (var i = 0; i < 8; i++) {"
13843 " ext_array[i] = 5;"
13845 "for (var i = 0; i < 8; i++) {"
13846 " ext_array[i] = NaN;"
13849 CHECK_EQ(0, result->Int32Value());
13850 CheckElementValue(isolate, 0, jsobj, 5);
13852 result = CompileRun("for (var i = 0; i < 8; i++) {"
13853 " ext_array[i] = 5;"
13855 "for (var i = 0; i < 8; i++) {"
13856 " ext_array[i] = Infinity;"
13859 int expected_value =
13860 (array_type == i::kExternalUint8ClampedArray) ? 255 : 0;
13861 CHECK_EQ(expected_value, result->Int32Value());
13862 CheckElementValue(isolate, expected_value, jsobj, 5);
13864 result = CompileRun("for (var i = 0; i < 8; i++) {"
13865 " ext_array[i] = 5;"
13867 "for (var i = 0; i < 8; i++) {"
13868 " ext_array[i] = -Infinity;"
13871 CHECK_EQ(0, result->Int32Value());
13872 CheckElementValue(isolate, 0, jsobj, 5);
13874 // Check truncation behavior of integral arrays.
13875 const char* unsigned_data =
13876 "var source_data = [0.6, 10.6];"
13877 "var expected_results = [0, 10];";
13878 const char* signed_data =
13879 "var source_data = [0.6, 10.6, -0.6, -10.6];"
13880 "var expected_results = [0, 10, 0, -10];";
13881 const char* pixel_data =
13882 "var source_data = [0.6, 10.6];"
13883 "var expected_results = [1, 11];";
13884 bool is_unsigned = (array_type == i::kExternalUint8Array ||
13885 array_type == i::kExternalUint16Array ||
13886 array_type == i::kExternalUint32Array);
13887 bool is_pixel_data = array_type == i::kExternalUint8ClampedArray;
13889 i::SNPrintF(test_buf,
13891 "var all_passed = true;"
13892 "for (var i = 0; i < source_data.length; i++) {"
13893 " for (var j = 0; j < 8; j++) {"
13894 " ext_array[j] = source_data[i];"
13896 " all_passed = all_passed &&"
13897 " (ext_array[5] == expected_results[i]);"
13902 (is_pixel_data ? pixel_data : signed_data)));
13903 result = CompileRun(test_buf.start());
13904 CHECK_EQ(true, result->BooleanValue());
13907 i::Handle<ExternalArrayClass> array(
13908 ExternalArrayClass::cast(jsobj->elements()));
13909 for (int i = 0; i < element_count; i++) {
13910 array->set(i, static_cast<ElementType>(i));
13913 // Test complex assignments
13914 result = CompileRun("function ee_op_test_complex_func(sum) {"
13915 " for (var i = 0; i < 40; ++i) {"
13916 " sum += (ext_array[i] += 1);"
13917 " sum += (ext_array[i] -= 1);"
13922 "for (var i=0;i<10000;++i) {"
13923 " sum=ee_op_test_complex_func(sum);"
13926 CHECK_EQ(16000000, result->Int32Value());
13928 // Test count operations
13929 result = CompileRun("function ee_op_test_count_func(sum) {"
13930 " for (var i = 0; i < 40; ++i) {"
13931 " sum += (++ext_array[i]);"
13932 " sum += (--ext_array[i]);"
13937 "for (var i=0;i<10000;++i) {"
13938 " sum=ee_op_test_count_func(sum);"
13941 CHECK_EQ(16000000, result->Int32Value());
13943 result = CompileRun("ext_array[3] = 33;"
13944 "delete ext_array[3];"
13946 CHECK_EQ(33, result->Int32Value());
13948 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
13949 "ext_array[2] = 12; ext_array[3] = 13;"
13950 "ext_array.__defineGetter__('2',"
13951 "function() { return 120; });"
13953 CHECK_EQ(12, result->Int32Value());
13955 result = CompileRun("var js_array = new Array(40);"
13956 "js_array[0] = 77;"
13958 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13960 result = CompileRun("ext_array[1] = 23;"
13961 "ext_array.__proto__ = [];"
13962 "js_array.__proto__ = ext_array;"
13963 "js_array.concat(ext_array);");
13964 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13965 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13967 result = CompileRun("ext_array[1] = 23;");
13968 CHECK_EQ(23, result->Int32Value());
13972 template <class FixedTypedArrayClass, i::ElementsKind elements_kind,
13974 static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type,
13975 ElementType low, ElementType high) {
13976 i::FLAG_allow_natives_syntax = true;
13977 LocalContext context;
13978 i::Isolate* isolate = CcTest::i_isolate();
13979 i::Factory* factory = isolate->factory();
13980 v8::HandleScope scope(context->GetIsolate());
13981 const int kElementCount = 260;
13982 i::Handle<i::JSTypedArray> jsobj =
13983 factory->NewJSTypedArray(elements_kind, kElementCount);
13984 i::Handle<FixedTypedArrayClass> fixed_array(
13985 FixedTypedArrayClass::cast(jsobj->elements()));
13986 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
13987 fixed_array->map()->instance_type());
13988 CHECK_EQ(kElementCount, fixed_array->length());
13989 CcTest::heap()->CollectAllGarbage();
13990 for (int i = 0; i < kElementCount; i++) {
13991 fixed_array->set(i, static_cast<ElementType>(i));
13993 // Force GC to trigger verification.
13994 CcTest::heap()->CollectAllGarbage();
13995 for (int i = 0; i < kElementCount; i++) {
13996 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
13997 static_cast<int64_t>(fixed_array->get_scalar(i)));
13999 v8::Handle<v8::Object> obj = v8::Utils::ToLocal(jsobj);
14001 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
14002 context.local(), obj, kElementCount, array_type,
14003 static_cast<int64_t>(low),
14004 static_cast<int64_t>(high));
14008 THREADED_TEST(FixedUint8Array) {
14009 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
14010 i::kExternalUint8Array, 0x0, 0xFF);
14014 THREADED_TEST(FixedUint8ClampedArray) {
14015 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
14016 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
14017 i::kExternalUint8ClampedArray, 0x0, 0xFF);
14021 THREADED_TEST(FixedInt8Array) {
14022 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
14023 i::kExternalInt8Array, -0x80, 0x7F);
14027 THREADED_TEST(FixedUint16Array) {
14028 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
14029 i::kExternalUint16Array, 0x0, 0xFFFF);
14033 THREADED_TEST(FixedInt16Array) {
14034 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
14035 i::kExternalInt16Array, -0x8000, 0x7FFF);
14039 THREADED_TEST(FixedUint32Array) {
14040 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
14041 i::kExternalUint32Array, 0x0, UINT_MAX);
14045 THREADED_TEST(FixedInt32Array) {
14046 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
14047 i::kExternalInt32Array, INT_MIN, INT_MAX);
14051 THREADED_TEST(FixedFloat32Array) {
14052 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
14053 i::kExternalFloat32Array, -500, 500);
14057 THREADED_TEST(FixedFloat64Array) {
14058 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
14059 i::kExternalFloat64Array, -500, 500);
14063 template <typename ElementType, typename TypedArray, class ExternalArrayClass,
14064 class ArrayBufferType>
14065 void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low,
14067 const int kElementCount = 50;
14069 i::ScopedVector<ElementType> backing_store(kElementCount+2);
14072 v8::Isolate* isolate = env->GetIsolate();
14073 v8::HandleScope handle_scope(isolate);
14075 Local<ArrayBufferType> ab =
14076 ArrayBufferType::New(isolate, backing_store.start(),
14077 (kElementCount + 2) * sizeof(ElementType));
14078 Local<TypedArray> ta =
14079 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
14080 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
14081 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
14082 CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
14083 CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
14084 CHECK(ab->Equals(ta->Buffer()));
14086 ElementType* data = backing_store.start() + 2;
14087 for (int i = 0; i < kElementCount; i++) {
14088 data[i] = static_cast<ElementType>(i);
14091 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
14092 env.local(), ta, kElementCount, array_type, low, high);
14096 THREADED_TEST(Uint8Array) {
14097 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array,
14098 v8::ArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
14102 THREADED_TEST(Int8Array) {
14103 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array,
14104 v8::ArrayBuffer>(i::kExternalInt8Array, -0x80, 0x7F);
14108 THREADED_TEST(Uint16Array) {
14109 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array,
14110 v8::ArrayBuffer>(i::kExternalUint16Array, 0, 0xFFFF);
14114 THREADED_TEST(Int16Array) {
14115 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array,
14116 v8::ArrayBuffer>(i::kExternalInt16Array, -0x8000,
14121 THREADED_TEST(Uint32Array) {
14122 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array,
14123 v8::ArrayBuffer>(i::kExternalUint32Array, 0, UINT_MAX);
14127 THREADED_TEST(Int32Array) {
14128 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array,
14129 v8::ArrayBuffer>(i::kExternalInt32Array, INT_MIN,
14134 THREADED_TEST(Float32Array) {
14135 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array,
14136 v8::ArrayBuffer>(i::kExternalFloat32Array, -500, 500);
14140 THREADED_TEST(Float64Array) {
14141 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array,
14142 v8::ArrayBuffer>(i::kExternalFloat64Array, -500, 500);
14146 THREADED_TEST(Uint8ClampedArray) {
14147 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
14148 i::ExternalUint8ClampedArray, v8::ArrayBuffer>(
14149 i::kExternalUint8ClampedArray, 0, 0xFF);
14153 THREADED_TEST(DataView) {
14154 const int kSize = 50;
14156 i::ScopedVector<uint8_t> backing_store(kSize+2);
14159 v8::Isolate* isolate = env->GetIsolate();
14160 v8::HandleScope handle_scope(isolate);
14162 Local<v8::ArrayBuffer> ab =
14163 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
14164 Local<v8::DataView> dv = v8::DataView::New(ab, 2, kSize);
14165 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
14166 CHECK_EQ(2u, dv->ByteOffset());
14167 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
14168 CHECK(ab->Equals(dv->Buffer()));
14172 THREADED_TEST(SkipArrayBufferBackingStoreDuringGC) {
14174 v8::Isolate* isolate = env->GetIsolate();
14175 v8::HandleScope handle_scope(isolate);
14177 // Make sure the pointer looks like a heap object
14178 uint8_t* store_ptr = reinterpret_cast<uint8_t*>(i::kHeapObjectTag);
14180 // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
14181 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
14183 // Should not crash
14184 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
14185 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
14186 CcTest::heap()->CollectAllGarbage();
14187 CcTest::heap()->CollectAllGarbage();
14189 // Should not move the pointer
14190 CHECK_EQ(ab->GetContents().Data(), store_ptr);
14194 THREADED_TEST(SharedUint8Array) {
14195 i::FLAG_harmony_sharedarraybuffer = true;
14196 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array,
14197 v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
14201 THREADED_TEST(SharedInt8Array) {
14202 i::FLAG_harmony_sharedarraybuffer = true;
14203 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array,
14204 v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
14209 THREADED_TEST(SharedUint16Array) {
14210 i::FLAG_harmony_sharedarraybuffer = true;
14211 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array,
14212 v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
14217 THREADED_TEST(SharedInt16Array) {
14218 i::FLAG_harmony_sharedarraybuffer = true;
14219 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array,
14220 v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
14225 THREADED_TEST(SharedUint32Array) {
14226 i::FLAG_harmony_sharedarraybuffer = true;
14227 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array,
14228 v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
14233 THREADED_TEST(SharedInt32Array) {
14234 i::FLAG_harmony_sharedarraybuffer = true;
14235 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array,
14236 v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
14241 THREADED_TEST(SharedFloat32Array) {
14242 i::FLAG_harmony_sharedarraybuffer = true;
14243 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array,
14244 v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
14249 THREADED_TEST(SharedFloat64Array) {
14250 i::FLAG_harmony_sharedarraybuffer = true;
14251 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array,
14252 v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
14257 THREADED_TEST(SharedUint8ClampedArray) {
14258 i::FLAG_harmony_sharedarraybuffer = true;
14259 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
14260 i::ExternalUint8ClampedArray, v8::SharedArrayBuffer>(
14261 i::kExternalUint8ClampedArray, 0, 0xFF);
14265 THREADED_TEST(SharedDataView) {
14266 i::FLAG_harmony_sharedarraybuffer = true;
14267 const int kSize = 50;
14269 i::ScopedVector<uint8_t> backing_store(kSize + 2);
14272 v8::Isolate* isolate = env->GetIsolate();
14273 v8::HandleScope handle_scope(isolate);
14275 Local<v8::SharedArrayBuffer> ab =
14276 v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
14277 Local<v8::DataView> dv =
14278 v8::DataView::New(ab, 2, kSize);
14279 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
14280 CHECK_EQ(2u, dv->ByteOffset());
14281 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
14282 CHECK(ab->Equals(dv->Buffer()));
14286 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
14287 THREADED_TEST(Is##View) { \
14288 LocalContext env; \
14289 v8::Isolate* isolate = env->GetIsolate(); \
14290 v8::HandleScope handle_scope(isolate); \
14292 Handle<Value> result = CompileRun( \
14293 "var ab = new ArrayBuffer(128);" \
14294 "new " #View "(ab)"); \
14295 CHECK(result->IsArrayBufferView()); \
14296 CHECK(result->Is##View()); \
14297 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
14300 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
14301 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
14302 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
14303 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
14304 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
14305 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
14306 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
14307 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
14308 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
14309 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
14311 #undef IS_ARRAY_BUFFER_VIEW_TEST
14315 THREADED_TEST(ScriptContextDependence) {
14317 v8::HandleScope scope(c1->GetIsolate());
14318 const char *source = "foo";
14319 v8::Handle<v8::Script> dep = v8_compile(source);
14320 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
14321 c1->GetIsolate(), source));
14322 v8::Handle<v8::UnboundScript> indep =
14323 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
14324 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
14325 v8::Integer::New(c1->GetIsolate(), 100));
14326 CHECK_EQ(dep->Run()->Int32Value(), 100);
14327 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
14329 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
14330 v8::Integer::New(c2->GetIsolate(), 101));
14331 CHECK_EQ(dep->Run()->Int32Value(), 100);
14332 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
14336 THREADED_TEST(StackTrace) {
14337 LocalContext context;
14338 v8::HandleScope scope(context->GetIsolate());
14339 v8::TryCatch try_catch(context->GetIsolate());
14340 const char *source = "function foo() { FAIL.FAIL; }; foo();";
14341 v8::Handle<v8::String> src =
14342 v8::String::NewFromUtf8(context->GetIsolate(), source);
14343 v8::Handle<v8::String> origin =
14344 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
14345 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
14346 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
14347 ->BindToCurrentContext()
14349 CHECK(try_catch.HasCaught());
14350 v8::String::Utf8Value stack(try_catch.StackTrace());
14351 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14355 // Checks that a StackFrame has certain expected values.
14356 void checkStackFrame(const char* expected_script_name,
14357 const char* expected_func_name, int expected_line_number,
14358 int expected_column, bool is_eval, bool is_constructor,
14359 v8::Handle<v8::StackFrame> frame) {
14360 v8::HandleScope scope(CcTest::isolate());
14361 v8::String::Utf8Value func_name(frame->GetFunctionName());
14362 v8::String::Utf8Value script_name(frame->GetScriptName());
14363 if (*script_name == NULL) {
14364 // The situation where there is no associated script, like for evals.
14365 CHECK(expected_script_name == NULL);
14367 CHECK(strstr(*script_name, expected_script_name) != NULL);
14369 CHECK(strstr(*func_name, expected_func_name) != NULL);
14370 CHECK_EQ(expected_line_number, frame->GetLineNumber());
14371 CHECK_EQ(expected_column, frame->GetColumn());
14372 CHECK_EQ(is_eval, frame->IsEval());
14373 CHECK_EQ(is_constructor, frame->IsConstructor());
14377 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
14378 v8::HandleScope scope(args.GetIsolate());
14379 const char* origin = "capture-stack-trace-test";
14380 const int kOverviewTest = 1;
14381 const int kDetailedTest = 2;
14383 DCHECK(args.Length() == 1);
14385 int testGroup = args[0]->Int32Value();
14386 if (testGroup == kOverviewTest) {
14387 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
14388 args.GetIsolate(), 10, v8::StackTrace::kOverview);
14389 CHECK_EQ(4, stackTrace->GetFrameCount());
14390 checkStackFrame(origin, "bar", 2, 10, false, false,
14391 stackTrace->GetFrame(0));
14392 checkStackFrame(origin, "foo", 6, 3, false, false,
14393 stackTrace->GetFrame(1));
14394 // This is the source string inside the eval which has the call to foo.
14395 checkStackFrame(NULL, "", 1, 1, false, false, stackTrace->GetFrame(2));
14396 // The last frame is an anonymous function which has the initial eval call.
14397 checkStackFrame(origin, "", 8, 7, false, false, stackTrace->GetFrame(3));
14399 CHECK(stackTrace->AsArray()->IsArray());
14400 } else if (testGroup == kDetailedTest) {
14401 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
14402 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
14403 CHECK_EQ(4, stackTrace->GetFrameCount());
14404 checkStackFrame(origin, "bat", 4, 22, false, false,
14405 stackTrace->GetFrame(0));
14406 checkStackFrame(origin, "baz", 8, 3, false, true,
14407 stackTrace->GetFrame(1));
14408 bool is_eval = true;
14409 // This is the source string inside the eval which has the call to baz.
14410 checkStackFrame(NULL, "", 1, 1, is_eval, false, stackTrace->GetFrame(2));
14411 // The last frame is an anonymous function which has the initial eval call.
14412 checkStackFrame(origin, "", 10, 1, false, false, stackTrace->GetFrame(3));
14414 CHECK(stackTrace->AsArray()->IsArray());
14419 // Tests the C++ StackTrace API.
14420 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
14421 // THREADED_TEST(CaptureStackTrace) {
14422 TEST(CaptureStackTrace) {
14423 v8::Isolate* isolate = CcTest::isolate();
14424 v8::HandleScope scope(isolate);
14425 v8::Handle<v8::String> origin =
14426 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
14427 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14428 templ->Set(v8_str("AnalyzeStackInNativeCode"),
14429 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
14430 LocalContext context(0, templ);
14432 // Test getting OVERVIEW information. Should ignore information that is not
14433 // script name, function name, line number, and column offset.
14434 const char *overview_source =
14435 "function bar() {\n"
14436 " var y; AnalyzeStackInNativeCode(1);\n"
14438 "function foo() {\n"
14442 "var x;eval('new foo();');";
14443 v8::Handle<v8::String> overview_src =
14444 v8::String::NewFromUtf8(isolate, overview_source);
14445 v8::ScriptCompiler::Source script_source(overview_src,
14446 v8::ScriptOrigin(origin));
14447 v8::Handle<Value> overview_result(
14448 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
14449 ->BindToCurrentContext()
14451 CHECK(!overview_result.IsEmpty());
14452 CHECK(overview_result->IsObject());
14454 // Test getting DETAILED information.
14455 const char *detailed_source =
14456 "function bat() {AnalyzeStackInNativeCode(2);\n"
14459 "function baz() {\n"
14462 "eval('new baz();');";
14463 v8::Handle<v8::String> detailed_src =
14464 v8::String::NewFromUtf8(isolate, detailed_source);
14465 // Make the script using a non-zero line and column offset.
14466 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
14467 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
14468 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
14469 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
14470 v8::Handle<v8::UnboundScript> detailed_script(
14471 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
14472 v8::Handle<Value> detailed_result(
14473 detailed_script->BindToCurrentContext()->Run());
14474 CHECK(!detailed_result.IsEmpty());
14475 CHECK(detailed_result->IsObject());
14479 static void StackTraceForUncaughtExceptionListener(
14480 v8::Handle<v8::Message> message,
14481 v8::Handle<Value>) {
14483 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14484 CHECK_EQ(2, stack_trace->GetFrameCount());
14485 checkStackFrame("origin", "foo", 2, 3, false, false,
14486 stack_trace->GetFrame(0));
14487 checkStackFrame("origin", "bar", 5, 3, false, false,
14488 stack_trace->GetFrame(1));
14492 TEST(CaptureStackTraceForUncaughtException) {
14495 v8::HandleScope scope(env->GetIsolate());
14496 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14497 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14499 CompileRunWithOrigin(
14500 "function foo() {\n"
14503 "function bar() {\n"
14507 v8::Local<v8::Object> global = env->Global();
14508 Local<Value> trouble = global->Get(v8_str("bar"));
14509 CHECK(trouble->IsFunction());
14510 Function::Cast(*trouble)->Call(global, 0, NULL);
14511 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14512 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14513 CHECK_EQ(1, report_count);
14517 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
14520 v8::HandleScope scope(env->GetIsolate());
14522 // Create an Error object first.
14523 CompileRunWithOrigin(
14524 "function foo() {\n"
14525 "e=new Error('err');\n"
14527 "function bar() {\n"
14532 v8::Local<v8::Object> global = env->Global();
14533 Local<Value> trouble = global->Get(v8_str("bar"));
14534 CHECK(trouble->IsFunction());
14535 Function::Cast(*trouble)->Call(global, 0, NULL);
14537 // Enable capturing detailed stack trace late, and throw the exception.
14538 // The detailed stack trace should be extracted from the simple stack.
14539 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14540 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14541 CompileRunWithOrigin("throw e", "origin");
14542 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14543 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14544 CHECK_EQ(1, report_count);
14548 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
14550 v8::HandleScope scope(env->GetIsolate());
14551 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
14553 v8::StackTrace::kDetailed);
14556 "var setters = ['column', 'lineNumber', 'scriptName',\n"
14557 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
14558 " 'isConstructor'];\n"
14559 "for (var i = 0; i < setters.length; i++) {\n"
14560 " var prop = setters[i];\n"
14561 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
14563 CompileRun("throw 'exception';");
14564 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14568 static void StackTraceFunctionNameListener(v8::Handle<v8::Message> message,
14569 v8::Handle<Value>) {
14570 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14571 CHECK_EQ(5, stack_trace->GetFrameCount());
14572 checkStackFrame("origin", "foo:0", 4, 7, false, false,
14573 stack_trace->GetFrame(0));
14574 checkStackFrame("origin", "foo:1", 5, 27, false, false,
14575 stack_trace->GetFrame(1));
14576 checkStackFrame("origin", "foo", 5, 27, false, false,
14577 stack_trace->GetFrame(2));
14578 checkStackFrame("origin", "foo", 5, 27, false, false,
14579 stack_trace->GetFrame(3));
14580 checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4));
14584 TEST(GetStackTraceContainsFunctionsWithFunctionName) {
14586 v8::HandleScope scope(env->GetIsolate());
14588 CompileRunWithOrigin(
14589 "function gen(name, counter) {\n"
14590 " var f = function foo() {\n"
14591 " if (counter === 0)\n"
14593 " gen(name, counter - 1)();\n"
14595 " if (counter == 3) {\n"
14596 " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
14598 " Object.defineProperty(f, 'name', {writable:true});\n"
14599 " if (counter == 2)\n"
14602 " f.name = name + ':' + counter;\n"
14608 v8::V8::AddMessageListener(StackTraceFunctionNameListener);
14609 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14610 CompileRunWithOrigin("gen('foo', 3)();", "origin");
14611 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14612 v8::V8::RemoveMessageListeners(StackTraceFunctionNameListener);
14616 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
14617 v8::Handle<v8::Value> data) {
14618 // Use the frame where JavaScript is called from.
14619 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14620 CHECK(!stack_trace.IsEmpty());
14621 int frame_count = stack_trace->GetFrameCount();
14622 CHECK_EQ(3, frame_count);
14623 int line_number[] = {1, 2, 5};
14624 for (int i = 0; i < frame_count; i++) {
14625 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14630 // Test that we only return the stack trace at the site where the exception
14631 // is first thrown (not where it is rethrown).
14632 TEST(RethrowStackTrace) {
14634 v8::HandleScope scope(env->GetIsolate());
14635 // We make sure that
14636 // - the stack trace of the ReferenceError in g() is reported.
14637 // - the stack trace is not overwritten when e1 is rethrown by t().
14638 // - the stack trace of e2 does not overwrite that of e1.
14639 const char* source =
14640 "function g() { error; } \n"
14641 "function f() { g(); } \n"
14642 "function t(e) { throw e; } \n"
14645 "} catch (e1) { \n"
14648 " } catch (e2) { \n"
14652 v8::V8::AddMessageListener(RethrowStackTraceHandler);
14653 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14654 CompileRun(source);
14655 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14656 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
14660 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
14661 v8::Handle<v8::Value> data) {
14662 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14663 CHECK(!stack_trace.IsEmpty());
14664 int frame_count = stack_trace->GetFrameCount();
14665 CHECK_EQ(2, frame_count);
14666 int line_number[] = {3, 7};
14667 for (int i = 0; i < frame_count; i++) {
14668 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14673 // Test that we do not recognize identity for primitive exceptions.
14674 TEST(RethrowPrimitiveStackTrace) {
14676 v8::HandleScope scope(env->GetIsolate());
14677 // We do not capture stack trace for non Error objects on creation time.
14678 // Instead, we capture the stack trace on last throw.
14679 const char* source =
14680 "function g() { throw 404; } \n"
14681 "function f() { g(); } \n"
14682 "function t(e) { throw e; } \n"
14685 "} catch (e1) { \n"
14688 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14689 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14690 CompileRun(source);
14691 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14692 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
14696 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
14697 v8::Handle<v8::Value> data) {
14698 // Use the frame where JavaScript is called from.
14699 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14700 CHECK(!stack_trace.IsEmpty());
14701 CHECK_EQ(1, stack_trace->GetFrameCount());
14702 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
14706 // Test that the stack trace is captured when the error object is created and
14707 // not where it is thrown.
14708 TEST(RethrowExistingStackTrace) {
14710 v8::HandleScope scope(env->GetIsolate());
14711 const char* source =
14712 "var e = new Error(); \n"
14714 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14715 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14716 CompileRun(source);
14717 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14718 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
14722 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
14723 v8::Handle<v8::Value> data) {
14724 // Use the frame where JavaScript is called from.
14725 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14726 CHECK(!stack_trace.IsEmpty());
14727 CHECK_EQ(1, stack_trace->GetFrameCount());
14728 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
14732 // Test that the stack trace is captured where the bogus Error object is thrown.
14733 TEST(RethrowBogusErrorStackTrace) {
14735 v8::HandleScope scope(env->GetIsolate());
14736 const char* source =
14737 "var e = {__proto__: new Error()} \n"
14739 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14740 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14741 CompileRun(source);
14742 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14743 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
14747 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
14748 int promise_reject_counter = 0;
14749 int promise_revoke_counter = 0;
14750 int promise_reject_msg_line_number = -1;
14751 int promise_reject_msg_column_number = -1;
14752 int promise_reject_line_number = -1;
14753 int promise_reject_column_number = -1;
14754 int promise_reject_frame_count = -1;
14756 void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
14757 if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
14758 promise_reject_counter++;
14759 CcTest::global()->Set(v8_str("rejected"), reject_message.GetPromise());
14760 CcTest::global()->Set(v8_str("value"), reject_message.GetValue());
14761 v8::Handle<v8::Message> message =
14762 v8::Exception::CreateMessage(reject_message.GetValue());
14763 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14765 promise_reject_msg_line_number = message->GetLineNumber();
14766 promise_reject_msg_column_number = message->GetStartColumn() + 1;
14768 if (!stack_trace.IsEmpty()) {
14769 promise_reject_frame_count = stack_trace->GetFrameCount();
14770 if (promise_reject_frame_count > 0) {
14771 CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
14772 promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
14773 promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn();
14775 promise_reject_line_number = -1;
14776 promise_reject_column_number = -1;
14780 promise_revoke_counter++;
14781 CcTest::global()->Set(v8_str("revoked"), reject_message.GetPromise());
14782 CHECK(reject_message.GetValue().IsEmpty());
14787 v8::Handle<v8::Promise> GetPromise(const char* name) {
14788 return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
14792 v8::Handle<v8::Value> RejectValue() {
14793 return CcTest::global()->Get(v8_str("value"));
14797 void ResetPromiseStates() {
14798 promise_reject_counter = 0;
14799 promise_revoke_counter = 0;
14800 promise_reject_msg_line_number = -1;
14801 promise_reject_msg_column_number = -1;
14802 promise_reject_line_number = -1;
14803 promise_reject_column_number = -1;
14804 promise_reject_frame_count = -1;
14805 CcTest::global()->Set(v8_str("rejected"), v8_str(""));
14806 CcTest::global()->Set(v8_str("value"), v8_str(""));
14807 CcTest::global()->Set(v8_str("revoked"), v8_str(""));
14811 TEST(PromiseRejectCallback) {
14813 v8::Isolate* isolate = env->GetIsolate();
14814 v8::HandleScope scope(isolate);
14816 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
14818 ResetPromiseStates();
14820 // Create promise p0.
14823 "var p0 = new Promise( \n"
14824 " function(res, rej) { \n"
14825 " reject = rej; \n"
14828 CHECK(!GetPromise("p0")->HasHandler());
14829 CHECK_EQ(0, promise_reject_counter);
14830 CHECK_EQ(0, promise_revoke_counter);
14832 // Add resolve handler (and default reject handler) to p0.
14833 CompileRun("var p1 = p0.then(function(){});");
14834 CHECK(GetPromise("p0")->HasHandler());
14835 CHECK(!GetPromise("p1")->HasHandler());
14836 CHECK_EQ(0, promise_reject_counter);
14837 CHECK_EQ(0, promise_revoke_counter);
14840 CompileRun("reject('ppp');");
14841 CHECK(GetPromise("p0")->HasHandler());
14842 CHECK(!GetPromise("p1")->HasHandler());
14843 CHECK_EQ(1, promise_reject_counter);
14844 CHECK_EQ(0, promise_revoke_counter);
14845 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
14846 CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
14847 CHECK(RejectValue()->Equals(v8_str("ppp")));
14849 // Reject p0 again. Callback is not triggered again.
14850 CompileRun("reject();");
14851 CHECK(GetPromise("p0")->HasHandler());
14852 CHECK(!GetPromise("p1")->HasHandler());
14853 CHECK_EQ(1, promise_reject_counter);
14854 CHECK_EQ(0, promise_revoke_counter);
14856 // Add resolve handler to p1.
14857 CompileRun("var p2 = p1.then(function(){});");
14858 CHECK(GetPromise("p0")->HasHandler());
14859 CHECK(GetPromise("p1")->HasHandler());
14860 CHECK(!GetPromise("p2")->HasHandler());
14861 CHECK_EQ(2, promise_reject_counter);
14862 CHECK_EQ(1, promise_revoke_counter);
14863 CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
14864 CHECK(RejectValue()->Equals(v8_str("ppp")));
14865 CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
14867 ResetPromiseStates();
14869 // Create promise q0.
14871 "var q0 = new Promise( \n"
14872 " function(res, rej) { \n"
14873 " reject = rej; \n"
14876 CHECK(!GetPromise("q0")->HasHandler());
14877 CHECK_EQ(0, promise_reject_counter);
14878 CHECK_EQ(0, promise_revoke_counter);
14880 // Add reject handler to q0.
14881 CompileRun("var q1 = q0.catch(function() {});");
14882 CHECK(GetPromise("q0")->HasHandler());
14883 CHECK(!GetPromise("q1")->HasHandler());
14884 CHECK_EQ(0, promise_reject_counter);
14885 CHECK_EQ(0, promise_revoke_counter);
14888 CompileRun("reject('qq')");
14889 CHECK(GetPromise("q0")->HasHandler());
14890 CHECK(!GetPromise("q1")->HasHandler());
14891 CHECK_EQ(0, promise_reject_counter);
14892 CHECK_EQ(0, promise_revoke_counter);
14894 // Add a new reject handler, which rejects by returning Promise.reject().
14895 // The returned promise q_ triggers a reject callback at first, only to
14896 // revoke it when returning it causes q2 to be rejected.
14899 "var q2 = q0.catch( \n"
14901 " q_ = Promise.reject('qqq'); \n"
14905 CHECK(GetPromise("q0")->HasHandler());
14906 CHECK(!GetPromise("q1")->HasHandler());
14907 CHECK(!GetPromise("q2")->HasHandler());
14908 CHECK(GetPromise("q_")->HasHandler());
14909 CHECK_EQ(2, promise_reject_counter);
14910 CHECK_EQ(1, promise_revoke_counter);
14911 CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
14912 CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
14913 CHECK(RejectValue()->Equals(v8_str("qqq")));
14915 // Add a reject handler to the resolved q1, which rejects by throwing.
14917 "var q3 = q1.then( \n"
14919 " throw 'qqqq'; \n"
14922 CHECK(GetPromise("q0")->HasHandler());
14923 CHECK(GetPromise("q1")->HasHandler());
14924 CHECK(!GetPromise("q2")->HasHandler());
14925 CHECK(!GetPromise("q3")->HasHandler());
14926 CHECK_EQ(3, promise_reject_counter);
14927 CHECK_EQ(1, promise_revoke_counter);
14928 CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
14929 CHECK(RejectValue()->Equals(v8_str("qqqq")));
14931 ResetPromiseStates();
14933 // Create promise r0, which has three handlers, two of which handle rejects.
14935 "var r0 = new Promise( \n"
14936 " function(res, rej) { \n"
14937 " reject = rej; \n"
14940 "var r1 = r0.catch(function() {}); \n"
14941 "var r2 = r0.then(function() {}); \n"
14942 "var r3 = r0.then(function() {}, \n"
14943 " function() {}); \n");
14944 CHECK(GetPromise("r0")->HasHandler());
14945 CHECK(!GetPromise("r1")->HasHandler());
14946 CHECK(!GetPromise("r2")->HasHandler());
14947 CHECK(!GetPromise("r3")->HasHandler());
14948 CHECK_EQ(0, promise_reject_counter);
14949 CHECK_EQ(0, promise_revoke_counter);
14952 CompileRun("reject('rrr')");
14953 CHECK(GetPromise("r0")->HasHandler());
14954 CHECK(!GetPromise("r1")->HasHandler());
14955 CHECK(!GetPromise("r2")->HasHandler());
14956 CHECK(!GetPromise("r3")->HasHandler());
14957 CHECK_EQ(1, promise_reject_counter);
14958 CHECK_EQ(0, promise_revoke_counter);
14959 CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
14960 CHECK(RejectValue()->Equals(v8_str("rrr")));
14962 // Add reject handler to r2.
14963 CompileRun("var r4 = r2.catch(function() {});");
14964 CHECK(GetPromise("r0")->HasHandler());
14965 CHECK(!GetPromise("r1")->HasHandler());
14966 CHECK(GetPromise("r2")->HasHandler());
14967 CHECK(!GetPromise("r3")->HasHandler());
14968 CHECK(!GetPromise("r4")->HasHandler());
14969 CHECK_EQ(1, promise_reject_counter);
14970 CHECK_EQ(1, promise_revoke_counter);
14971 CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
14972 CHECK(RejectValue()->Equals(v8_str("rrr")));
14974 // Add reject handlers to r4.
14975 CompileRun("var r5 = r4.then(function() {}, function() {});");
14976 CHECK(GetPromise("r0")->HasHandler());
14977 CHECK(!GetPromise("r1")->HasHandler());
14978 CHECK(GetPromise("r2")->HasHandler());
14979 CHECK(!GetPromise("r3")->HasHandler());
14980 CHECK(GetPromise("r4")->HasHandler());
14981 CHECK(!GetPromise("r5")->HasHandler());
14982 CHECK_EQ(1, promise_reject_counter);
14983 CHECK_EQ(1, promise_revoke_counter);
14985 ResetPromiseStates();
14987 // Create promise s0, which has three handlers, none of which handle rejects.
14989 "var s0 = new Promise( \n"
14990 " function(res, rej) { \n"
14991 " reject = rej; \n"
14994 "var s1 = s0.then(function() {}); \n"
14995 "var s2 = s0.then(function() {}); \n"
14996 "var s3 = s0.then(function() {}); \n");
14997 CHECK(GetPromise("s0")->HasHandler());
14998 CHECK(!GetPromise("s1")->HasHandler());
14999 CHECK(!GetPromise("s2")->HasHandler());
15000 CHECK(!GetPromise("s3")->HasHandler());
15001 CHECK_EQ(0, promise_reject_counter);
15002 CHECK_EQ(0, promise_revoke_counter);
15005 CompileRun("reject('sss')");
15006 CHECK(GetPromise("s0")->HasHandler());
15007 CHECK(!GetPromise("s1")->HasHandler());
15008 CHECK(!GetPromise("s2")->HasHandler());
15009 CHECK(!GetPromise("s3")->HasHandler());
15010 CHECK_EQ(3, promise_reject_counter);
15011 CHECK_EQ(0, promise_revoke_counter);
15012 CHECK(RejectValue()->Equals(v8_str("sss")));
15014 // Test stack frames.
15015 V8::SetCaptureStackTraceForUncaughtExceptions(true);
15017 ResetPromiseStates();
15019 // Create promise t0, which is rejected in the constructor with an error.
15020 CompileRunWithOrigin(
15021 "var t0 = new Promise( \n"
15022 " function(res, rej) { \n"
15023 " reference_error; \n"
15027 CHECK(!GetPromise("t0")->HasHandler());
15028 CHECK_EQ(1, promise_reject_counter);
15029 CHECK_EQ(0, promise_revoke_counter);
15030 CHECK_EQ(2, promise_reject_frame_count);
15031 CHECK_EQ(3, promise_reject_line_number);
15032 CHECK_EQ(5, promise_reject_column_number);
15033 CHECK_EQ(3, promise_reject_msg_line_number);
15034 CHECK_EQ(5, promise_reject_msg_column_number);
15036 ResetPromiseStates();
15038 // Create promise u0 and chain u1 to it, which is rejected via throw.
15039 CompileRunWithOrigin(
15040 "var u0 = Promise.resolve(); \n"
15041 "var u1 = u0.then( \n"
15043 " (function() { \n"
15044 " throw new Error(); \n"
15049 CHECK(GetPromise("u0")->HasHandler());
15050 CHECK(!GetPromise("u1")->HasHandler());
15051 CHECK_EQ(1, promise_reject_counter);
15052 CHECK_EQ(0, promise_revoke_counter);
15053 CHECK_EQ(2, promise_reject_frame_count);
15054 CHECK_EQ(5, promise_reject_line_number);
15055 CHECK_EQ(23, promise_reject_column_number);
15056 CHECK_EQ(5, promise_reject_msg_line_number);
15057 CHECK_EQ(23, promise_reject_msg_column_number);
15059 // Throw in u3, which handles u1's rejection.
15060 CompileRunWithOrigin(
15061 "function f() { \n"
15062 " return (function() { \n"
15063 " return new Error(); \n"
15066 "var u2 = Promise.reject(f()); \n"
15067 "var u3 = u1.catch( \n"
15073 CHECK(GetPromise("u0")->HasHandler());
15074 CHECK(GetPromise("u1")->HasHandler());
15075 CHECK(GetPromise("u2")->HasHandler());
15076 CHECK(!GetPromise("u3")->HasHandler());
15077 CHECK_EQ(3, promise_reject_counter);
15078 CHECK_EQ(2, promise_revoke_counter);
15079 CHECK_EQ(3, promise_reject_frame_count);
15080 CHECK_EQ(3, promise_reject_line_number);
15081 CHECK_EQ(12, promise_reject_column_number);
15082 CHECK_EQ(3, promise_reject_msg_line_number);
15083 CHECK_EQ(12, promise_reject_msg_column_number);
15085 ResetPromiseStates();
15087 // Create promise rejected promise v0, which is incorrectly handled by v1
15088 // via chaining cycle.
15089 CompileRunWithOrigin(
15090 "var v0 = Promise.reject(); \n"
15091 "var v1 = v0.catch( \n"
15097 CHECK(GetPromise("v0")->HasHandler());
15098 CHECK(!GetPromise("v1")->HasHandler());
15099 CHECK_EQ(2, promise_reject_counter);
15100 CHECK_EQ(1, promise_revoke_counter);
15101 CHECK_EQ(0, promise_reject_frame_count);
15102 CHECK_EQ(-1, promise_reject_line_number);
15103 CHECK_EQ(-1, promise_reject_column_number);
15105 ResetPromiseStates();
15107 // Create promise t1, which rejects by throwing syntax error from eval.
15108 CompileRunWithOrigin(
15109 "var t1 = new Promise( \n"
15110 " function(res, rej) { \n"
15111 " var content = '\\n\\\n"
15113 " eval(content); \n"
15117 CHECK(!GetPromise("t1")->HasHandler());
15118 CHECK_EQ(1, promise_reject_counter);
15119 CHECK_EQ(0, promise_revoke_counter);
15120 CHECK_EQ(2, promise_reject_frame_count);
15121 CHECK_EQ(5, promise_reject_line_number);
15122 CHECK_EQ(10, promise_reject_column_number);
15123 CHECK_EQ(2, promise_reject_msg_line_number);
15124 CHECK_EQ(7, promise_reject_msg_column_number);
15128 void AnalyzeStackOfEvalWithSourceURL(
15129 const v8::FunctionCallbackInfo<v8::Value>& args) {
15130 v8::HandleScope scope(args.GetIsolate());
15131 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15132 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15133 CHECK_EQ(5, stackTrace->GetFrameCount());
15134 v8::Handle<v8::String> url = v8_str("eval_url");
15135 for (int i = 0; i < 3; i++) {
15136 v8::Handle<v8::String> name =
15137 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15138 CHECK(!name.IsEmpty());
15139 CHECK(url->Equals(name));
15144 TEST(SourceURLInStackTrace) {
15145 v8::Isolate* isolate = CcTest::isolate();
15146 v8::HandleScope scope(isolate);
15147 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15148 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
15149 v8::FunctionTemplate::New(isolate,
15150 AnalyzeStackOfEvalWithSourceURL));
15151 LocalContext context(0, templ);
15153 const char *source =
15154 "function outer() {\n"
15155 "function bar() {\n"
15156 " AnalyzeStackOfEvalWithSourceURL();\n"
15158 "function foo() {\n"
15164 "eval('(' + outer +')()%s');";
15166 i::ScopedVector<char> code(1024);
15167 i::SNPrintF(code, source, "//# sourceURL=eval_url");
15168 CHECK(CompileRun(code.start())->IsUndefined());
15169 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
15170 CHECK(CompileRun(code.start())->IsUndefined());
15174 static int scriptIdInStack[2];
15176 void AnalyzeScriptIdInStack(
15177 const v8::FunctionCallbackInfo<v8::Value>& args) {
15178 v8::HandleScope scope(args.GetIsolate());
15179 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15180 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
15181 CHECK_EQ(2, stackTrace->GetFrameCount());
15182 for (int i = 0; i < 2; i++) {
15183 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
15188 TEST(ScriptIdInStackTrace) {
15189 v8::Isolate* isolate = CcTest::isolate();
15190 v8::HandleScope scope(isolate);
15191 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15192 templ->Set(v8_str("AnalyzeScriptIdInStack"),
15193 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
15194 LocalContext context(0, templ);
15196 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
15198 "function foo() {\n"
15199 " AnalyzeScriptIdInStack();"
15202 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
15204 for (int i = 0; i < 2; i++) {
15205 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
15206 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
15211 void AnalyzeStackOfInlineScriptWithSourceURL(
15212 const v8::FunctionCallbackInfo<v8::Value>& args) {
15213 v8::HandleScope scope(args.GetIsolate());
15214 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15215 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15216 CHECK_EQ(4, stackTrace->GetFrameCount());
15217 v8::Handle<v8::String> url = v8_str("source_url");
15218 for (int i = 0; i < 3; i++) {
15219 v8::Handle<v8::String> name =
15220 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15221 CHECK(!name.IsEmpty());
15222 CHECK(url->Equals(name));
15227 TEST(InlineScriptWithSourceURLInStackTrace) {
15228 v8::Isolate* isolate = CcTest::isolate();
15229 v8::HandleScope scope(isolate);
15230 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15231 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
15232 v8::FunctionTemplate::New(
15233 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
15234 LocalContext context(0, templ);
15236 const char *source =
15237 "function outer() {\n"
15238 "function bar() {\n"
15239 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
15241 "function foo() {\n"
15249 i::ScopedVector<char> code(1024);
15250 i::SNPrintF(code, source, "//# sourceURL=source_url");
15251 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15252 i::SNPrintF(code, source, "//@ sourceURL=source_url");
15253 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15257 void AnalyzeStackOfDynamicScriptWithSourceURL(
15258 const v8::FunctionCallbackInfo<v8::Value>& args) {
15259 v8::HandleScope scope(args.GetIsolate());
15260 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15261 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15262 CHECK_EQ(4, stackTrace->GetFrameCount());
15263 v8::Handle<v8::String> url = v8_str("source_url");
15264 for (int i = 0; i < 3; i++) {
15265 v8::Handle<v8::String> name =
15266 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15267 CHECK(!name.IsEmpty());
15268 CHECK(url->Equals(name));
15273 TEST(DynamicWithSourceURLInStackTrace) {
15274 v8::Isolate* isolate = CcTest::isolate();
15275 v8::HandleScope scope(isolate);
15276 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15277 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
15278 v8::FunctionTemplate::New(
15279 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
15280 LocalContext context(0, templ);
15282 const char *source =
15283 "function outer() {\n"
15284 "function bar() {\n"
15285 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
15287 "function foo() {\n"
15295 i::ScopedVector<char> code(1024);
15296 i::SNPrintF(code, source, "//# sourceURL=source_url");
15297 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15298 i::SNPrintF(code, source, "//@ sourceURL=source_url");
15299 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15303 TEST(DynamicWithSourceURLInStackTraceString) {
15304 LocalContext context;
15305 v8::HandleScope scope(context->GetIsolate());
15307 const char *source =
15308 "function outer() {\n"
15309 " function foo() {\n"
15316 i::ScopedVector<char> code(1024);
15317 i::SNPrintF(code, source, "//# sourceURL=source_url");
15318 v8::TryCatch try_catch(context->GetIsolate());
15319 CompileRunWithOrigin(code.start(), "", 0, 0);
15320 CHECK(try_catch.HasCaught());
15321 v8::String::Utf8Value stack(try_catch.StackTrace());
15322 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
15326 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15327 LocalContext context;
15328 v8::HandleScope scope(context->GetIsolate());
15330 const char *source =
15331 "function outer() {\n"
15332 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
15333 " //# sourceURL=source_url\";\n"
15334 " eval(scriptContents);\n"
15337 "//# sourceURL=outer_url";
15339 v8::TryCatch try_catch(context->GetIsolate());
15340 CompileRun(source);
15341 CHECK(try_catch.HasCaught());
15343 Local<v8::Message> message = try_catch.Message();
15344 Handle<Value> sourceURL =
15345 message->GetScriptOrigin().ResourceName();
15346 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15350 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15351 LocalContext context;
15352 v8::HandleScope scope(context->GetIsolate());
15354 const char *source =
15355 "function outer() {\n"
15356 " var scriptContents = \"function boo(){ boo(); }\\\n"
15357 " //# sourceURL=source_url\";\n"
15358 " eval(scriptContents);\n"
15361 "//# sourceURL=outer_url";
15363 v8::TryCatch try_catch(context->GetIsolate());
15364 CompileRun(source);
15365 CHECK(try_catch.HasCaught());
15367 Local<v8::Message> message = try_catch.Message();
15368 Handle<Value> sourceURL =
15369 message->GetScriptOrigin().ResourceName();
15370 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15374 static void CreateGarbageInOldSpace() {
15375 i::Factory* factory = CcTest::i_isolate()->factory();
15376 v8::HandleScope scope(CcTest::isolate());
15377 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
15378 for (int i = 0; i < 1000; i++) {
15379 factory->NewFixedArray(1000, i::TENURED);
15384 // Test that idle notification can be handled and eventually collects garbage.
15385 TEST(TestIdleNotification) {
15386 if (!i::FLAG_incremental_marking) return;
15387 const intptr_t MB = 1024 * 1024;
15388 const double IdlePauseInSeconds = 1.0;
15390 v8::HandleScope scope(env->GetIsolate());
15391 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
15392 CreateGarbageInOldSpace();
15393 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
15394 CHECK_GT(size_with_garbage, initial_size + MB);
15395 bool finished = false;
15396 for (int i = 0; i < 200 && !finished; i++) {
15397 if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) {
15398 CcTest::heap()->StartIdleIncrementalMarking();
15400 finished = env->GetIsolate()->IdleNotificationDeadline(
15401 (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
15402 static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
15403 IdlePauseInSeconds);
15404 if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
15405 CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
15408 intptr_t final_size = CcTest::heap()->SizeOfObjects();
15410 CHECK_LT(final_size, initial_size + 1);
15414 TEST(Regress2333) {
15416 for (int i = 0; i < 3; i++) {
15417 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
15421 static uint32_t* stack_limit;
15423 static void GetStackLimitCallback(
15424 const v8::FunctionCallbackInfo<v8::Value>& args) {
15425 stack_limit = reinterpret_cast<uint32_t*>(
15426 CcTest::i_isolate()->stack_guard()->real_climit());
15430 // Uses the address of a local variable to determine the stack top now.
15431 // Given a size, returns an address that is that far from the current
15433 static uint32_t* ComputeStackLimit(uint32_t size) {
15434 uint32_t* answer = &size - (size / sizeof(size));
15435 // If the size is very large and the stack is very near the bottom of
15436 // memory then the calculation above may wrap around and give an address
15437 // that is above the (downwards-growing) stack. In that case we return
15438 // a very low address.
15439 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
15444 // We need at least 165kB for an x64 debug build with clang and ASAN.
15445 static const int stack_breathing_room = 256 * i::KB;
15448 TEST(SetStackLimit) {
15449 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
15451 // Set stack limit.
15452 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
15454 // Execute a script.
15456 v8::HandleScope scope(env->GetIsolate());
15457 Local<v8::FunctionTemplate> fun_templ =
15458 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
15459 Local<Function> fun = fun_templ->GetFunction();
15460 env->Global()->Set(v8_str("get_stack_limit"), fun);
15461 CompileRun("get_stack_limit();");
15463 CHECK(stack_limit == set_limit);
15467 TEST(SetStackLimitInThread) {
15468 uint32_t* set_limit;
15470 v8::Locker locker(CcTest::isolate());
15471 set_limit = ComputeStackLimit(stack_breathing_room);
15473 // Set stack limit.
15474 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
15476 // Execute a script.
15477 v8::HandleScope scope(CcTest::isolate());
15479 Local<v8::FunctionTemplate> fun_templ =
15480 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
15481 Local<Function> fun = fun_templ->GetFunction();
15482 env->Global()->Set(v8_str("get_stack_limit"), fun);
15483 CompileRun("get_stack_limit();");
15485 CHECK(stack_limit == set_limit);
15488 v8::Locker locker(CcTest::isolate());
15489 CHECK(stack_limit == set_limit);
15494 THREADED_TEST(GetHeapStatistics) {
15496 v8::HandleScope scope(c1->GetIsolate());
15497 v8::HeapStatistics heap_statistics;
15498 CHECK_EQ(0u, heap_statistics.total_heap_size());
15499 CHECK_EQ(0u, heap_statistics.used_heap_size());
15500 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
15501 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
15502 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
15506 class VisitorImpl : public v8::ExternalResourceVisitor {
15508 explicit VisitorImpl(TestResource** resource) {
15509 for (int i = 0; i < 4; i++) {
15510 resource_[i] = resource[i];
15511 found_resource_[i] = false;
15514 virtual ~VisitorImpl() {}
15515 virtual void VisitExternalString(v8::Handle<v8::String> string) {
15516 if (!string->IsExternal()) {
15517 CHECK(string->IsExternalOneByte());
15520 v8::String::ExternalStringResource* resource =
15521 string->GetExternalStringResource();
15523 for (int i = 0; i < 4; i++) {
15524 if (resource_[i] == resource) {
15525 CHECK(!found_resource_[i]);
15526 found_resource_[i] = true;
15530 void CheckVisitedResources() {
15531 for (int i = 0; i < 4; i++) {
15532 CHECK(found_resource_[i]);
15537 v8::String::ExternalStringResource* resource_[4];
15538 bool found_resource_[4];
15542 TEST(ExternalizeOldSpaceTwoByteCons) {
15543 v8::Isolate* isolate = CcTest::isolate();
15545 v8::HandleScope scope(isolate);
15546 v8::Local<v8::String> cons =
15547 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
15548 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
15549 CcTest::heap()->CollectAllAvailableGarbage();
15550 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
15552 TestResource* resource = new TestResource(
15553 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
15554 cons->MakeExternal(resource);
15556 CHECK(cons->IsExternal());
15557 CHECK_EQ(resource, cons->GetExternalStringResource());
15558 String::Encoding encoding;
15559 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
15560 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
15564 TEST(ExternalizeOldSpaceOneByteCons) {
15565 v8::Isolate* isolate = CcTest::isolate();
15567 v8::HandleScope scope(isolate);
15568 v8::Local<v8::String> cons =
15569 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
15570 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
15571 CcTest::heap()->CollectAllAvailableGarbage();
15572 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
15574 TestOneByteResource* resource =
15575 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
15576 cons->MakeExternal(resource);
15578 CHECK(cons->IsExternalOneByte());
15579 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
15580 String::Encoding encoding;
15581 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
15582 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
15586 TEST(VisitExternalStrings) {
15587 v8::Isolate* isolate = CcTest::isolate();
15589 v8::HandleScope scope(isolate);
15590 const char* string = "Some string";
15591 uint16_t* two_byte_string = AsciiToTwoByteString(string);
15592 TestResource* resource[4];
15593 resource[0] = new TestResource(two_byte_string);
15594 v8::Local<v8::String> string0 =
15595 v8::String::NewExternal(env->GetIsolate(), resource[0]);
15596 resource[1] = new TestResource(two_byte_string, NULL, false);
15597 v8::Local<v8::String> string1 =
15598 v8::String::NewExternal(env->GetIsolate(), resource[1]);
15600 // Externalized symbol.
15601 resource[2] = new TestResource(two_byte_string, NULL, false);
15602 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
15603 env->GetIsolate(), string, v8::String::kInternalizedString);
15604 CHECK(string2->MakeExternal(resource[2]));
15606 // Symbolized External.
15607 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
15608 v8::Local<v8::String> string3 =
15609 v8::String::NewExternal(env->GetIsolate(), resource[3]);
15610 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
15611 // Turn into a symbol.
15612 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
15613 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
15614 string3_i).is_null());
15615 CHECK(string3_i->IsInternalizedString());
15617 // We need to add usages for string* to avoid warnings in GCC 4.7
15618 CHECK(string0->IsExternal());
15619 CHECK(string1->IsExternal());
15620 CHECK(string2->IsExternal());
15621 CHECK(string3->IsExternal());
15623 VisitorImpl visitor(resource);
15624 v8::V8::VisitExternalResources(&visitor);
15625 visitor.CheckVisitedResources();
15629 TEST(ExternalStringCollectedAtTearDown) {
15631 v8::Isolate::CreateParams create_params;
15632 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
15633 v8::Isolate* isolate = v8::Isolate::New(create_params);
15634 { v8::Isolate::Scope isolate_scope(isolate);
15635 v8::HandleScope handle_scope(isolate);
15636 const char* s = "One string to test them all, one string to find them.";
15637 TestOneByteResource* inscription =
15638 new TestOneByteResource(i::StrDup(s), &destroyed);
15639 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
15640 // Ring is still alive. Orcs are roaming freely across our lands.
15641 CHECK_EQ(0, destroyed);
15645 isolate->Dispose();
15646 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
15647 CHECK_EQ(1, destroyed);
15651 TEST(ExternalInternalizedStringCollectedAtTearDown) {
15653 v8::Isolate::CreateParams create_params;
15654 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
15655 v8::Isolate* isolate = v8::Isolate::New(create_params);
15656 { v8::Isolate::Scope isolate_scope(isolate);
15657 LocalContext env(isolate);
15658 v8::HandleScope handle_scope(isolate);
15659 CompileRun("var ring = 'One string to test them all';");
15660 const char* s = "One string to test them all";
15661 TestOneByteResource* inscription =
15662 new TestOneByteResource(i::StrDup(s), &destroyed);
15663 v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
15664 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
15665 ring->MakeExternal(inscription);
15666 // Ring is still alive. Orcs are roaming freely across our lands.
15667 CHECK_EQ(0, destroyed);
15671 isolate->Dispose();
15672 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
15673 CHECK_EQ(1, destroyed);
15677 TEST(ExternalInternalizedStringCollectedAtGC) {
15679 { LocalContext env;
15680 v8::HandleScope handle_scope(env->GetIsolate());
15681 CompileRun("var ring = 'One string to test them all';");
15682 const char* s = "One string to test them all";
15683 TestOneByteResource* inscription =
15684 new TestOneByteResource(i::StrDup(s), &destroyed);
15685 v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
15686 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
15687 ring->MakeExternal(inscription);
15688 // Ring is still alive. Orcs are roaming freely across our lands.
15689 CHECK_EQ(0, destroyed);
15693 // Garbage collector deals swift blows to evil.
15694 CcTest::i_isolate()->compilation_cache()->Clear();
15695 CcTest::heap()->CollectAllAvailableGarbage();
15697 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
15698 CHECK_EQ(1, destroyed);
15702 static double DoubleFromBits(uint64_t value) {
15704 i::MemCopy(&target, &value, sizeof(target));
15709 static uint64_t DoubleToBits(double value) {
15711 i::MemCopy(&target, &value, sizeof(target));
15716 static double DoubleToDateTime(double input) {
15717 double date_limit = 864e13;
15718 if (std::isnan(input) || input < -date_limit || input > date_limit) {
15719 return std::numeric_limits<double>::quiet_NaN();
15721 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
15725 // We don't have a consistent way to write 64-bit constants syntactically, so we
15726 // split them into two 32-bit constants and combine them programmatically.
15727 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
15728 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
15732 THREADED_TEST(QuietSignalingNaNs) {
15733 LocalContext context;
15734 v8::Isolate* isolate = context->GetIsolate();
15735 v8::HandleScope scope(isolate);
15736 v8::TryCatch try_catch(isolate);
15738 // Special double values.
15739 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
15740 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
15741 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
15742 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
15743 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
15744 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
15745 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
15747 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
15748 // on either side of the epoch.
15749 double date_limit = 864e13;
15751 double test_values[] = {
15773 int num_test_values = 20;
15775 for (int i = 0; i < num_test_values; i++) {
15776 double test_value = test_values[i];
15778 // Check that Number::New preserves non-NaNs and quiets SNaNs.
15779 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
15780 double stored_number = number->NumberValue();
15781 if (!std::isnan(test_value)) {
15782 CHECK_EQ(test_value, stored_number);
15784 uint64_t stored_bits = DoubleToBits(stored_number);
15785 // Check if quiet nan (bits 51..62 all set).
15786 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
15787 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
15788 // Most significant fraction bit for quiet nan is set to 0
15789 // on MIPS architecture. Allowed by IEEE-754.
15790 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15792 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
15796 // Check that Date::New preserves non-NaNs in the date range and
15798 v8::Handle<v8::Value> date =
15799 v8::Date::New(isolate, test_value);
15800 double expected_stored_date = DoubleToDateTime(test_value);
15801 double stored_date = date->NumberValue();
15802 if (!std::isnan(expected_stored_date)) {
15803 CHECK_EQ(expected_stored_date, stored_date);
15805 uint64_t stored_bits = DoubleToBits(stored_date);
15806 // Check if quiet nan (bits 51..62 all set).
15807 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
15808 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
15809 // Most significant fraction bit for quiet nan is set to 0
15810 // on MIPS architecture. Allowed by IEEE-754.
15811 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15813 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
15820 static void SpaghettiIncident(
15821 const v8::FunctionCallbackInfo<v8::Value>& args) {
15822 v8::HandleScope scope(args.GetIsolate());
15823 v8::TryCatch tc(args.GetIsolate());
15824 v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
15826 if (tc.HasCaught())
15831 // Test that an exception can be propagated down through a spaghetti
15832 // stack using ReThrow.
15833 THREADED_TEST(SpaghettiStackReThrow) {
15834 v8::Isolate* isolate = CcTest::isolate();
15835 v8::HandleScope scope(isolate);
15836 LocalContext context;
15837 context->Global()->Set(
15838 v8::String::NewFromUtf8(isolate, "s"),
15839 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
15840 v8::TryCatch try_catch(isolate);
15844 " toString: function () {"
15854 CHECK(try_catch.HasCaught());
15855 v8::String::Utf8Value value(try_catch.Exception());
15856 CHECK_EQ(0, strcmp(*value, "Hey!"));
15861 v8::V8::Initialize();
15862 v8::Isolate* isolate = CcTest::isolate();
15863 i::FLAG_retain_maps_for_n_gc = 0;
15864 v8::HandleScope scope(isolate);
15865 v8::Local<Context> other_context;
15868 // Create a context used to keep the code from aging in the compilation
15870 other_context = Context::New(isolate);
15872 // Context-dependent context data creates reference from the compilation
15873 // cache to the global object.
15874 const char* source_simple = "1";
15876 v8::HandleScope scope(isolate);
15877 v8::Local<Context> context = Context::New(isolate);
15880 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
15881 context->SetEmbedderData(0, obj);
15882 CompileRun(source_simple);
15885 isolate->ContextDisposedNotification();
15886 for (gc_count = 1; gc_count < 10; gc_count++) {
15887 other_context->Enter();
15888 CompileRun(source_simple);
15889 other_context->Exit();
15890 CcTest::heap()->CollectAllGarbage();
15891 if (GetGlobalObjectsCount() == 1) break;
15893 CHECK_GE(2, gc_count);
15894 CHECK_EQ(1, GetGlobalObjectsCount());
15896 // Eval in a function creates reference from the compilation cache to the
15898 const char* source_eval = "function f(){eval('1')}; f()";
15900 v8::HandleScope scope(isolate);
15901 v8::Local<Context> context = Context::New(isolate);
15904 CompileRun(source_eval);
15907 isolate->ContextDisposedNotification();
15908 for (gc_count = 1; gc_count < 10; gc_count++) {
15909 other_context->Enter();
15910 CompileRun(source_eval);
15911 other_context->Exit();
15912 CcTest::heap()->CollectAllGarbage();
15913 if (GetGlobalObjectsCount() == 1) break;
15915 CHECK_GE(2, gc_count);
15916 CHECK_EQ(1, GetGlobalObjectsCount());
15918 // Looking up the line number for an exception creates reference from the
15919 // compilation cache to the global object.
15920 const char* source_exception = "function f(){throw 1;} f()";
15922 v8::HandleScope scope(isolate);
15923 v8::Local<Context> context = Context::New(isolate);
15926 v8::TryCatch try_catch(isolate);
15927 CompileRun(source_exception);
15928 CHECK(try_catch.HasCaught());
15929 v8::Handle<v8::Message> message = try_catch.Message();
15930 CHECK(!message.IsEmpty());
15931 CHECK_EQ(1, message->GetLineNumber());
15934 isolate->ContextDisposedNotification();
15935 for (gc_count = 1; gc_count < 10; gc_count++) {
15936 other_context->Enter();
15937 CompileRun(source_exception);
15938 other_context->Exit();
15939 CcTest::heap()->CollectAllGarbage();
15940 if (GetGlobalObjectsCount() == 1) break;
15942 CHECK_GE(2, gc_count);
15943 CHECK_EQ(1, GetGlobalObjectsCount());
15945 isolate->ContextDisposedNotification();
15949 THREADED_TEST(ScriptOrigin) {
15951 v8::HandleScope scope(env->GetIsolate());
15952 v8::ScriptOrigin origin = v8::ScriptOrigin(
15953 v8::String::NewFromUtf8(env->GetIsolate(), "test"),
15954 v8::Integer::New(env->GetIsolate(), 1),
15955 v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
15956 v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()),
15957 v8::String::NewFromUtf8(env->GetIsolate(), "http://sourceMapUrl"),
15958 v8::True(env->GetIsolate()));
15959 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
15960 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
15961 v8::Script::Compile(script, &origin)->Run();
15962 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15963 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
15964 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15965 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
15967 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
15968 CHECK_EQ(0, strcmp("test",
15969 *v8::String::Utf8Value(script_origin_f.ResourceName())));
15970 CHECK_EQ(1, script_origin_f.ResourceLineOffset()->Int32Value());
15971 CHECK(script_origin_f.Options().IsSharedCrossOrigin());
15972 CHECK(script_origin_f.Options().IsEmbedderDebugScript());
15973 CHECK(script_origin_f.Options().IsOpaque());
15974 printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
15976 CHECK_EQ(0, strcmp("http://sourceMapUrl",
15977 *v8::String::Utf8Value(script_origin_f.SourceMapUrl())));
15979 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
15980 CHECK_EQ(0, strcmp("test",
15981 *v8::String::Utf8Value(script_origin_g.ResourceName())));
15982 CHECK_EQ(1, script_origin_g.ResourceLineOffset()->Int32Value());
15983 CHECK(script_origin_g.Options().IsSharedCrossOrigin());
15984 CHECK(script_origin_g.Options().IsEmbedderDebugScript());
15985 CHECK(script_origin_g.Options().IsOpaque());
15986 CHECK_EQ(0, strcmp("http://sourceMapUrl",
15987 *v8::String::Utf8Value(script_origin_g.SourceMapUrl())));
15991 THREADED_TEST(FunctionGetInferredName) {
15993 v8::HandleScope scope(env->GetIsolate());
15994 v8::ScriptOrigin origin =
15995 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
15996 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
15998 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
15999 v8::Script::Compile(script, &origin)->Run();
16000 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16001 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16003 strcmp("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())));
16007 THREADED_TEST(FunctionGetDisplayName) {
16009 v8::HandleScope scope(env->GetIsolate());
16010 const char* code = "var error = false;"
16011 "function a() { this.x = 1; };"
16012 "a.displayName = 'display_a';"
16013 "var b = (function() {"
16014 " var f = function() { this.x = 2; };"
16015 " f.displayName = 'display_b';"
16018 "var c = function() {};"
16019 "c.__defineGetter__('displayName', function() {"
16021 " throw new Error();"
16024 "d.__defineGetter__('displayName', function() {"
16026 " return 'wrong_display_name';"
16029 "e.displayName = 'wrong_display_name';"
16030 "e.__defineSetter__('displayName', function() {"
16032 " throw new Error();"
16035 "f.displayName = { 'foo': 6, toString: function() {"
16037 " return 'wrong_display_name';"
16039 "var g = function() {"
16040 " arguments.callee.displayName = 'set_in_runtime';"
16043 v8::ScriptOrigin origin =
16044 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16045 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
16047 v8::Local<v8::Value> error =
16048 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
16049 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
16050 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
16051 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
16052 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
16053 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
16054 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
16055 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
16056 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
16057 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
16058 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
16059 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16060 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16061 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16062 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16063 CHECK_EQ(false, error->BooleanValue());
16064 CHECK_EQ(0, strcmp("display_a", *v8::String::Utf8Value(a->GetDisplayName())));
16065 CHECK_EQ(0, strcmp("display_b", *v8::String::Utf8Value(b->GetDisplayName())));
16066 CHECK(c->GetDisplayName()->IsUndefined());
16067 CHECK(d->GetDisplayName()->IsUndefined());
16068 CHECK(e->GetDisplayName()->IsUndefined());
16069 CHECK(f->GetDisplayName()->IsUndefined());
16071 0, strcmp("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())));
16075 THREADED_TEST(ScriptLineNumber) {
16077 v8::HandleScope scope(env->GetIsolate());
16078 v8::ScriptOrigin origin =
16079 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16080 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16081 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
16082 v8::Script::Compile(script, &origin)->Run();
16083 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16084 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16085 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16086 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16087 CHECK_EQ(0, f->GetScriptLineNumber());
16088 CHECK_EQ(2, g->GetScriptLineNumber());
16092 THREADED_TEST(ScriptColumnNumber) {
16094 v8::Isolate* isolate = env->GetIsolate();
16095 v8::HandleScope scope(isolate);
16096 v8::ScriptOrigin origin =
16097 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16098 v8::Integer::New(isolate, 3),
16099 v8::Integer::New(isolate, 2));
16100 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16101 isolate, "function foo() {}\n\n function bar() {}");
16102 v8::Script::Compile(script, &origin)->Run();
16103 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16104 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16105 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16106 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16107 CHECK_EQ(14, foo->GetScriptColumnNumber());
16108 CHECK_EQ(17, bar->GetScriptColumnNumber());
16112 THREADED_TEST(FunctionIsBuiltin) {
16114 v8::Isolate* isolate = env->GetIsolate();
16115 v8::HandleScope scope(isolate);
16116 v8::Local<v8::Function> f;
16117 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
16118 CHECK(f->IsBuiltin());
16119 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
16120 CHECK(f->IsBuiltin());
16121 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
16122 CHECK(f->IsBuiltin());
16123 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
16124 CHECK(f->IsBuiltin());
16125 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
16126 CHECK(!f->IsBuiltin());
16130 THREADED_TEST(FunctionGetScriptId) {
16132 v8::Isolate* isolate = env->GetIsolate();
16133 v8::HandleScope scope(isolate);
16134 v8::ScriptOrigin origin =
16135 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16136 v8::Integer::New(isolate, 3),
16137 v8::Integer::New(isolate, 2));
16138 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
16139 isolate, "function foo() {}\n\n function bar() {}");
16140 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
16142 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16143 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16144 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16145 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16146 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
16147 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
16151 THREADED_TEST(FunctionGetBoundFunction) {
16153 v8::HandleScope scope(env->GetIsolate());
16154 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
16155 env->GetIsolate(), "test"));
16156 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16158 "var a = new Object();\n"
16160 "function f () { return this.x };\n"
16161 "var g = f.bind(a);\n"
16163 v8::Script::Compile(script, &origin)->Run();
16164 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16165 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16166 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16167 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16168 CHECK(g->GetBoundFunction()->IsFunction());
16169 Local<v8::Function> original_function = Local<v8::Function>::Cast(
16170 g->GetBoundFunction());
16171 CHECK(f->GetName()->Equals(original_function->GetName()));
16172 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
16173 CHECK_EQ(f->GetScriptColumnNumber(),
16174 original_function->GetScriptColumnNumber());
16178 static void GetterWhichReturns42(
16179 Local<String> name,
16180 const v8::PropertyCallbackInfo<v8::Value>& info) {
16181 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16182 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16183 info.GetReturnValue().Set(v8_num(42));
16187 static void SetterWhichSetsYOnThisTo23(
16188 Local<String> name,
16189 Local<Value> value,
16190 const v8::PropertyCallbackInfo<void>& info) {
16191 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16192 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16193 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16197 void FooGetInterceptor(Local<Name> name,
16198 const v8::PropertyCallbackInfo<v8::Value>& info) {
16199 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16200 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16201 if (!name->Equals(v8_str("foo"))) return;
16202 info.GetReturnValue().Set(v8_num(42));
16206 void FooSetInterceptor(Local<Name> name, Local<Value> value,
16207 const v8::PropertyCallbackInfo<v8::Value>& info) {
16208 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16209 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16210 if (!name->Equals(v8_str("foo"))) return;
16211 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16212 info.GetReturnValue().Set(v8_num(23));
16216 TEST(SetterOnConstructorPrototype) {
16217 v8::Isolate* isolate = CcTest::isolate();
16218 v8::HandleScope scope(isolate);
16219 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16220 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16221 SetterWhichSetsYOnThisTo23);
16222 LocalContext context;
16223 context->Global()->Set(v8_str("P"), templ->NewInstance());
16224 CompileRun("function C1() {"
16227 "C1.prototype = P;"
16231 "C2.prototype = { };"
16232 "C2.prototype.__proto__ = P;");
16234 v8::Local<v8::Script> script;
16235 script = v8_compile("new C1();");
16236 for (int i = 0; i < 10; i++) {
16237 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16238 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16239 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16242 script = v8_compile("new C2();");
16243 for (int i = 0; i < 10; i++) {
16244 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16245 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
16246 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
16251 static void NamedPropertyGetterWhichReturns42(
16252 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
16253 info.GetReturnValue().Set(v8_num(42));
16257 static void NamedPropertySetterWhichSetsYOnThisTo23(
16258 Local<Name> name, Local<Value> value,
16259 const v8::PropertyCallbackInfo<v8::Value>& info) {
16260 if (name->Equals(v8_str("x"))) {
16261 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16266 THREADED_TEST(InterceptorOnConstructorPrototype) {
16267 v8::Isolate* isolate = CcTest::isolate();
16268 v8::HandleScope scope(isolate);
16269 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16270 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
16271 NamedPropertyGetterWhichReturns42,
16272 NamedPropertySetterWhichSetsYOnThisTo23));
16273 LocalContext context;
16274 context->Global()->Set(v8_str("P"), templ->NewInstance());
16275 CompileRun("function C1() {"
16278 "C1.prototype = P;"
16282 "C2.prototype = { };"
16283 "C2.prototype.__proto__ = P;");
16285 v8::Local<v8::Script> script;
16286 script = v8_compile("new C1();");
16287 for (int i = 0; i < 10; i++) {
16288 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16289 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16290 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16293 script = v8_compile("new C2();");
16294 for (int i = 0; i < 10; i++) {
16295 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16296 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
16297 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
16303 const char* source = "function C1() {"
16306 "C1.prototype = P;";
16308 LocalContext context;
16309 v8::Isolate* isolate = context->GetIsolate();
16310 v8::HandleScope scope(isolate);
16311 v8::Local<v8::Script> script;
16313 // Use a simple object as prototype.
16314 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
16315 prototype->Set(v8_str("y"), v8_num(42));
16316 context->Global()->Set(v8_str("P"), prototype);
16318 // This compile will add the code to the compilation cache.
16319 CompileRun(source);
16321 script = v8_compile("new C1();");
16322 // Allow enough iterations for the inobject slack tracking logic
16323 // to finalize instance size and install the fast construct stub.
16324 for (int i = 0; i < 256; i++) {
16325 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16326 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16327 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16330 // Use an API object with accessors as prototype.
16331 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16332 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16333 SetterWhichSetsYOnThisTo23);
16334 context->Global()->Set(v8_str("P"), templ->NewInstance());
16336 // This compile will get the code from the compilation cache.
16337 CompileRun(source);
16339 script = v8_compile("new C1();");
16340 for (int i = 0; i < 10; i++) {
16341 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16342 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16343 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16347 v8::Isolate* gc_callbacks_isolate = NULL;
16348 int prologue_call_count = 0;
16349 int epilogue_call_count = 0;
16350 int prologue_call_count_second = 0;
16351 int epilogue_call_count_second = 0;
16352 int prologue_call_count_alloc = 0;
16353 int epilogue_call_count_alloc = 0;
16355 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16356 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16357 ++prologue_call_count;
16361 void PrologueCallback(v8::Isolate* isolate,
16363 v8::GCCallbackFlags flags) {
16364 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16365 CHECK_EQ(gc_callbacks_isolate, isolate);
16366 ++prologue_call_count;
16370 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16371 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16372 ++epilogue_call_count;
16376 void EpilogueCallback(v8::Isolate* isolate,
16378 v8::GCCallbackFlags flags) {
16379 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16380 CHECK_EQ(gc_callbacks_isolate, isolate);
16381 ++epilogue_call_count;
16385 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
16386 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16387 ++prologue_call_count_second;
16391 void PrologueCallbackSecond(v8::Isolate* isolate,
16393 v8::GCCallbackFlags flags) {
16394 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16395 CHECK_EQ(gc_callbacks_isolate, isolate);
16396 ++prologue_call_count_second;
16400 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
16401 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16402 ++epilogue_call_count_second;
16406 void EpilogueCallbackSecond(v8::Isolate* isolate,
16408 v8::GCCallbackFlags flags) {
16409 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16410 CHECK_EQ(gc_callbacks_isolate, isolate);
16411 ++epilogue_call_count_second;
16415 void PrologueCallbackAlloc(v8::Isolate* isolate,
16417 v8::GCCallbackFlags flags) {
16418 v8::HandleScope scope(isolate);
16420 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16421 CHECK_EQ(gc_callbacks_isolate, isolate);
16422 ++prologue_call_count_alloc;
16424 // Simulate full heap to see if we will reenter this callback
16425 SimulateFullSpace(CcTest::heap()->new_space());
16427 Local<Object> obj = Object::New(isolate);
16428 CHECK(!obj.IsEmpty());
16430 CcTest::heap()->CollectAllGarbage(
16431 i::Heap::kAbortIncrementalMarkingMask);
16435 void EpilogueCallbackAlloc(v8::Isolate* isolate,
16437 v8::GCCallbackFlags flags) {
16438 v8::HandleScope scope(isolate);
16440 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16441 CHECK_EQ(gc_callbacks_isolate, isolate);
16442 ++epilogue_call_count_alloc;
16444 // Simulate full heap to see if we will reenter this callback
16445 SimulateFullSpace(CcTest::heap()->new_space());
16447 Local<Object> obj = Object::New(isolate);
16448 CHECK(!obj.IsEmpty());
16450 CcTest::heap()->CollectAllGarbage(
16451 i::Heap::kAbortIncrementalMarkingMask);
16455 TEST(GCCallbacksOld) {
16456 LocalContext context;
16458 v8::V8::AddGCPrologueCallback(PrologueCallback);
16459 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
16460 CHECK_EQ(0, prologue_call_count);
16461 CHECK_EQ(0, epilogue_call_count);
16462 CcTest::heap()->CollectAllGarbage();
16463 CHECK_EQ(1, prologue_call_count);
16464 CHECK_EQ(1, epilogue_call_count);
16465 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
16466 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
16467 CcTest::heap()->CollectAllGarbage();
16468 CHECK_EQ(2, prologue_call_count);
16469 CHECK_EQ(2, epilogue_call_count);
16470 CHECK_EQ(1, prologue_call_count_second);
16471 CHECK_EQ(1, epilogue_call_count_second);
16472 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
16473 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
16474 CcTest::heap()->CollectAllGarbage();
16475 CHECK_EQ(2, prologue_call_count);
16476 CHECK_EQ(2, epilogue_call_count);
16477 CHECK_EQ(2, prologue_call_count_second);
16478 CHECK_EQ(2, epilogue_call_count_second);
16479 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
16480 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
16481 CcTest::heap()->CollectAllGarbage();
16482 CHECK_EQ(2, prologue_call_count);
16483 CHECK_EQ(2, epilogue_call_count);
16484 CHECK_EQ(2, prologue_call_count_second);
16485 CHECK_EQ(2, epilogue_call_count_second);
16489 TEST(GCCallbacks) {
16490 LocalContext context;
16491 v8::Isolate* isolate = context->GetIsolate();
16492 gc_callbacks_isolate = isolate;
16493 isolate->AddGCPrologueCallback(PrologueCallback);
16494 isolate->AddGCEpilogueCallback(EpilogueCallback);
16495 CHECK_EQ(0, prologue_call_count);
16496 CHECK_EQ(0, epilogue_call_count);
16497 CcTest::heap()->CollectAllGarbage();
16498 CHECK_EQ(1, prologue_call_count);
16499 CHECK_EQ(1, epilogue_call_count);
16500 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
16501 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
16502 CcTest::heap()->CollectAllGarbage();
16503 CHECK_EQ(2, prologue_call_count);
16504 CHECK_EQ(2, epilogue_call_count);
16505 CHECK_EQ(1, prologue_call_count_second);
16506 CHECK_EQ(1, epilogue_call_count_second);
16507 isolate->RemoveGCPrologueCallback(PrologueCallback);
16508 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
16509 CcTest::heap()->CollectAllGarbage();
16510 CHECK_EQ(2, prologue_call_count);
16511 CHECK_EQ(2, epilogue_call_count);
16512 CHECK_EQ(2, prologue_call_count_second);
16513 CHECK_EQ(2, epilogue_call_count_second);
16514 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
16515 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
16516 CcTest::heap()->CollectAllGarbage();
16517 CHECK_EQ(2, prologue_call_count);
16518 CHECK_EQ(2, epilogue_call_count);
16519 CHECK_EQ(2, prologue_call_count_second);
16520 CHECK_EQ(2, epilogue_call_count_second);
16522 CHECK_EQ(0, prologue_call_count_alloc);
16523 CHECK_EQ(0, epilogue_call_count_alloc);
16524 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
16525 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
16526 CcTest::heap()->CollectAllGarbage(
16527 i::Heap::kAbortIncrementalMarkingMask);
16528 CHECK_EQ(1, prologue_call_count_alloc);
16529 CHECK_EQ(1, epilogue_call_count_alloc);
16530 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
16531 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
16535 THREADED_TEST(AddToJSFunctionResultCache) {
16536 i::FLAG_stress_compaction = false;
16537 i::FLAG_allow_natives_syntax = true;
16538 v8::HandleScope scope(CcTest::isolate());
16540 LocalContext context;
16546 " var r0 = %_GetFromCache(0, key0);"
16547 " var r1 = %_GetFromCache(0, key1);"
16548 " var r0_ = %_GetFromCache(0, key0);"
16550 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
16551 " var r1_ = %_GetFromCache(0, key1);"
16553 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
16554 " return 'PASSED';"
16556 CcTest::heap()->ClearJSFunctionResultCaches();
16557 ExpectString(code, "PASSED");
16561 THREADED_TEST(FillJSFunctionResultCache) {
16562 i::FLAG_allow_natives_syntax = true;
16563 LocalContext context;
16564 v8::HandleScope scope(context->GetIsolate());
16569 " var r = %_GetFromCache(0, k);"
16570 " for (var i = 0; i < 16; i++) {"
16571 " %_GetFromCache(0, 'a' + i);"
16573 " if (r === %_GetFromCache(0, k))"
16574 " return 'FAILED: k0CacheSize is too small';"
16575 " return 'PASSED';"
16577 CcTest::heap()->ClearJSFunctionResultCaches();
16578 ExpectString(code, "PASSED");
16582 THREADED_TEST(RoundRobinGetFromCache) {
16583 i::FLAG_allow_natives_syntax = true;
16584 LocalContext context;
16585 v8::HandleScope scope(context->GetIsolate());
16590 " for (var i = 0; i < 16; i++) keys.push(i);"
16591 " var values = [];"
16592 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
16593 " for (var i = 0; i < 16; i++) {"
16594 " var v = %_GetFromCache(0, keys[i]);"
16595 " if (v.toString() !== values[i].toString())"
16596 " return 'Wrong value for ' + "
16597 " keys[i] + ': ' + v + ' vs. ' + values[i];"
16599 " return 'PASSED';"
16601 CcTest::heap()->ClearJSFunctionResultCaches();
16602 ExpectString(code, "PASSED");
16606 THREADED_TEST(ReverseGetFromCache) {
16607 i::FLAG_allow_natives_syntax = true;
16608 LocalContext context;
16609 v8::HandleScope scope(context->GetIsolate());
16614 " for (var i = 0; i < 16; i++) keys.push(i);"
16615 " var values = [];"
16616 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
16617 " for (var i = 15; i >= 16; i--) {"
16618 " var v = %_GetFromCache(0, keys[i]);"
16619 " if (v !== values[i])"
16620 " return 'Wrong value for ' + "
16621 " keys[i] + ': ' + v + ' vs. ' + values[i];"
16623 " return 'PASSED';"
16625 CcTest::heap()->ClearJSFunctionResultCaches();
16626 ExpectString(code, "PASSED");
16630 THREADED_TEST(TestEviction) {
16631 i::FLAG_allow_natives_syntax = true;
16632 LocalContext context;
16633 v8::HandleScope scope(context->GetIsolate());
16637 " for (var i = 0; i < 2*16; i++) {"
16638 " %_GetFromCache(0, 'a' + i);"
16640 " return 'PASSED';"
16642 CcTest::heap()->ClearJSFunctionResultCaches();
16643 ExpectString(code, "PASSED");
16647 THREADED_TEST(TwoByteStringInOneByteCons) {
16648 // See Chromium issue 47824.
16649 LocalContext context;
16650 v8::HandleScope scope(context->GetIsolate());
16652 const char* init_code =
16653 "var str1 = 'abelspendabel';"
16654 "var str2 = str1 + str1 + str1;"
16656 Local<Value> result = CompileRun(init_code);
16658 Local<Value> indexof = CompileRun("str2.indexOf('els')");
16659 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
16661 CHECK(result->IsString());
16662 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
16663 int length = string->length();
16664 CHECK(string->IsOneByteRepresentation());
16666 i::Handle<i::String> flat_string = i::String::Flatten(string);
16668 CHECK(string->IsOneByteRepresentation());
16669 CHECK(flat_string->IsOneByteRepresentation());
16671 // Create external resource.
16672 uint16_t* uc16_buffer = new uint16_t[length + 1];
16674 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
16675 uc16_buffer[length] = 0;
16677 TestResource resource(uc16_buffer);
16679 flat_string->MakeExternal(&resource);
16681 CHECK(flat_string->IsTwoByteRepresentation());
16683 // If the cons string has been short-circuited, skip the following checks.
16684 if (!string.is_identical_to(flat_string)) {
16685 // At this point, we should have a Cons string which is flat and one-byte,
16686 // with a first half that is a two-byte string (although it only contains
16687 // one-byte characters). This is a valid sequence of steps, and it can
16688 // happen in real pages.
16689 CHECK(string->IsOneByteRepresentation());
16690 i::ConsString* cons = i::ConsString::cast(*string);
16691 CHECK_EQ(0, cons->second()->length());
16692 CHECK(cons->first()->IsTwoByteRepresentation());
16695 // Check that some string operations work.
16698 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
16699 CHECK_EQ(6, reresult->Int32Value());
16702 reresult = CompileRun("str2.match(/abe./g).length;");
16703 CHECK_EQ(6, reresult->Int32Value());
16705 reresult = CompileRun("str2.search(/bel/g);");
16706 CHECK_EQ(1, reresult->Int32Value());
16708 reresult = CompileRun("str2.search(/be./g);");
16709 CHECK_EQ(1, reresult->Int32Value());
16711 ExpectTrue("/bel/g.test(str2);");
16713 ExpectTrue("/be./g.test(str2);");
16715 reresult = CompileRun("/bel/g.exec(str2);");
16716 CHECK(!reresult->IsNull());
16718 reresult = CompileRun("/be./g.exec(str2);");
16719 CHECK(!reresult->IsNull());
16721 ExpectString("str2.substring(2, 10);", "elspenda");
16723 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
16725 ExpectString("str2.charAt(2);", "e");
16727 ExpectObject("str2.indexOf('els');", indexof);
16729 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
16731 reresult = CompileRun("str2.charCodeAt(2);");
16732 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
16736 TEST(ContainsOnlyOneByte) {
16737 v8::V8::Initialize();
16738 v8::Isolate* isolate = CcTest::isolate();
16739 v8::HandleScope scope(isolate);
16740 // Make a buffer long enough that it won't automatically be converted.
16741 const int length = 512;
16742 // Ensure word aligned assignment.
16743 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
16744 i::SmartArrayPointer<uintptr_t>
16745 aligned_contents(new uintptr_t[aligned_length]);
16746 uint16_t* string_contents =
16747 reinterpret_cast<uint16_t*>(aligned_contents.get());
16748 // Set to contain only one byte.
16749 for (int i = 0; i < length-1; i++) {
16750 string_contents[i] = 0x41;
16752 string_contents[length-1] = 0;
16754 Handle<String> string =
16755 String::NewExternal(isolate,
16756 new TestResource(string_contents, NULL, false));
16757 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
16758 // Counter example.
16759 string = String::NewFromTwoByte(isolate, string_contents);
16760 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
16761 // Test left right and balanced cons strings.
16762 Handle<String> base = String::NewFromUtf8(isolate, "a");
16763 Handle<String> left = base;
16764 Handle<String> right = base;
16765 for (int i = 0; i < 1000; i++) {
16766 left = String::Concat(base, left);
16767 right = String::Concat(right, base);
16769 Handle<String> balanced = String::Concat(left, base);
16770 balanced = String::Concat(balanced, right);
16771 Handle<String> cons_strings[] = {left, balanced, right};
16772 Handle<String> two_byte =
16773 String::NewExternal(isolate,
16774 new TestResource(string_contents, NULL, false));
16775 USE(two_byte); USE(cons_strings);
16776 for (size_t i = 0; i < arraysize(cons_strings); i++) {
16777 // Base assumptions.
16778 string = cons_strings[i];
16779 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
16780 // Test left and right concatentation.
16781 string = String::Concat(two_byte, cons_strings[i]);
16782 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
16783 string = String::Concat(cons_strings[i], two_byte);
16784 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
16786 // Set bits in different positions
16787 // for strings of different lengths and alignments.
16788 for (int alignment = 0; alignment < 7; alignment++) {
16789 for (int size = 2; alignment + size < length; size *= 2) {
16790 int zero_offset = size + alignment;
16791 string_contents[zero_offset] = 0;
16792 for (int i = 0; i < size; i++) {
16793 int shift = 8 + (i % 7);
16794 string_contents[alignment + i] = 1 << shift;
16795 string = String::NewExternal(
16797 new TestResource(string_contents + alignment, NULL, false));
16798 CHECK_EQ(size, string->Length());
16799 CHECK(!string->ContainsOnlyOneByte());
16800 string_contents[alignment + i] = 0x41;
16802 string_contents[zero_offset] = 0x41;
16808 // Failed access check callback that performs a GC on each invocation.
16809 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
16810 v8::AccessType type,
16811 Local<v8::Value> data) {
16812 CcTest::heap()->CollectAllGarbage();
16813 CcTest::isolate()->ThrowException(
16814 v8::Exception::Error(v8_str("cross context")));
16818 TEST(GCInFailedAccessCheckCallback) {
16819 // Install a failed access check callback that performs a GC on each
16820 // invocation. Then force the callback to be called from va
16822 v8::V8::Initialize();
16823 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
16825 v8::Isolate* isolate = CcTest::isolate();
16826 v8::HandleScope scope(isolate);
16828 // Create an ObjectTemplate for global objects and install access
16829 // check callbacks that will block access.
16830 v8::Handle<v8::ObjectTemplate> global_template =
16831 v8::ObjectTemplate::New(isolate);
16832 global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL,
16833 v8::Handle<v8::Value>());
16835 // Create a context and set an x property on it's global object.
16836 LocalContext context0(NULL, global_template);
16837 context0->Global()->Set(v8_str("x"), v8_num(42));
16838 v8::Handle<v8::Object> global0 = context0->Global();
16840 // Create a context with a different security token so that the
16841 // failed access check callback will be called on each access.
16842 LocalContext context1(NULL, global_template);
16843 context1->Global()->Set(v8_str("other"), global0);
16845 v8::TryCatch try_catch(isolate);
16847 // Get property with failed access check.
16848 CHECK(CompileRun("other.x").IsEmpty());
16849 CHECK(try_catch.HasCaught());
16852 // Get element with failed access check.
16853 CHECK(CompileRun("other[0]").IsEmpty());
16854 CHECK(try_catch.HasCaught());
16857 // Set property with failed access check.
16858 CHECK(CompileRun("other.x = new Object()").IsEmpty());
16859 CHECK(try_catch.HasCaught());
16862 // Set element with failed access check.
16863 CHECK(CompileRun("other[0] = new Object()").IsEmpty());
16864 CHECK(try_catch.HasCaught());
16867 // Get property attribute with failed access check.
16868 CHECK(CompileRun("\'x\' in other").IsEmpty());
16869 CHECK(try_catch.HasCaught());
16872 // Get property attribute for element with failed access check.
16873 CHECK(CompileRun("0 in other").IsEmpty());
16874 CHECK(try_catch.HasCaught());
16877 // Delete property.
16878 CHECK(CompileRun("delete other.x").IsEmpty());
16879 CHECK(try_catch.HasCaught());
16883 CHECK_EQ(false, global0->Delete(0));
16887 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
16889 // Define JavaScript accessor.
16891 "Object.prototype.__defineGetter__.call("
16892 " other, \'x\', function() { return 42; })").IsEmpty());
16893 CHECK(try_catch.HasCaught());
16898 "Object.prototype.__lookupGetter__.call("
16899 " other, \'x\')").IsEmpty());
16900 CHECK(try_catch.HasCaught());
16905 "Object.prototype.hasOwnProperty.call("
16906 "other, \'0\')").IsEmpty());
16907 CHECK(try_catch.HasCaught());
16910 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
16911 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
16912 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
16914 // Reset the failed access check callback so it does not influence
16915 // the other tests.
16916 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
16920 TEST(IsolateNewDispose) {
16921 v8::Isolate* current_isolate = CcTest::isolate();
16922 v8::Isolate::CreateParams create_params;
16923 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
16924 v8::Isolate* isolate = v8::Isolate::New(create_params);
16925 CHECK(isolate != NULL);
16926 CHECK(current_isolate != isolate);
16927 CHECK(current_isolate == CcTest::isolate());
16929 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16930 last_location = last_message = NULL;
16931 isolate->Dispose();
16932 CHECK(!last_location);
16933 CHECK(!last_message);
16937 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
16938 v8::Isolate::CreateParams create_params;
16939 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
16940 v8::Isolate* isolate = v8::Isolate::New(create_params);
16942 v8::Isolate::Scope i_scope(isolate);
16943 v8::HandleScope scope(isolate);
16944 LocalContext context(isolate);
16945 // Run something in this isolate.
16946 ExpectTrue("true");
16947 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16948 last_location = last_message = NULL;
16949 // Still entered, should fail.
16950 isolate->Dispose();
16951 CHECK(last_location);
16952 CHECK(last_message);
16954 isolate->Dispose();
16958 static void BreakArrayGuarantees(const char* script) {
16959 v8::Isolate::CreateParams create_params;
16960 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
16961 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
16963 v8::Persistent<v8::Context> context1;
16965 v8::HandleScope scope(isolate1);
16966 context1.Reset(isolate1, Context::New(isolate1));
16970 v8::HandleScope scope(isolate1);
16971 v8::Local<v8::Context> context =
16972 v8::Local<v8::Context>::New(isolate1, context1);
16973 v8::Context::Scope context_scope(context);
16974 v8::internal::Isolate* i_isolate =
16975 reinterpret_cast<v8::internal::Isolate*>(isolate1);
16976 CHECK_EQ(true, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
16977 // Run something in new isolate.
16978 CompileRun(script);
16979 CHECK_EQ(false, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
16982 isolate1->Dispose();
16986 TEST(VerifyArrayPrototypeGuarantees) {
16987 // Break fast array hole handling by element changes.
16988 BreakArrayGuarantees("[].__proto__[1] = 3;");
16989 BreakArrayGuarantees("Object.prototype[3] = 'three';");
16990 BreakArrayGuarantees("Array.prototype.push(1);");
16991 BreakArrayGuarantees("Array.prototype.unshift(1);");
16992 // Break fast array hole handling by changing length.
16993 BreakArrayGuarantees("Array.prototype.length = 30;");
16994 // Break fast array hole handling by prototype structure changes.
16995 BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
16996 // By sending elements to dictionary mode.
16997 BreakArrayGuarantees("Object.freeze(Array.prototype);");
16998 BreakArrayGuarantees("Object.freeze(Object.prototype);");
16999 BreakArrayGuarantees(
17000 "Object.defineProperty(Array.prototype, 0, {"
17001 " get: function() { return 3; }});");
17002 BreakArrayGuarantees(
17003 "Object.defineProperty(Object.prototype, 0, {"
17004 " get: function() { return 3; }});");
17008 TEST(RunTwoIsolatesOnSingleThread) {
17010 v8::Isolate::CreateParams create_params;
17011 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17012 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
17014 v8::Persistent<v8::Context> context1;
17016 v8::HandleScope scope(isolate1);
17017 context1.Reset(isolate1, Context::New(isolate1));
17021 v8::HandleScope scope(isolate1);
17022 v8::Local<v8::Context> context =
17023 v8::Local<v8::Context>::New(isolate1, context1);
17024 v8::Context::Scope context_scope(context);
17025 // Run something in new isolate.
17026 CompileRun("var foo = 'isolate 1';");
17027 ExpectString("function f() { return foo; }; f()", "isolate 1");
17031 v8::Isolate* isolate2 = v8::Isolate::New(create_params);
17032 v8::Persistent<v8::Context> context2;
17035 v8::Isolate::Scope iscope(isolate2);
17036 v8::HandleScope scope(isolate2);
17037 context2.Reset(isolate2, Context::New(isolate2));
17038 v8::Local<v8::Context> context =
17039 v8::Local<v8::Context>::New(isolate2, context2);
17040 v8::Context::Scope context_scope(context);
17042 // Run something in new isolate.
17043 CompileRun("var foo = 'isolate 2';");
17044 ExpectString("function f() { return foo; }; f()", "isolate 2");
17048 v8::HandleScope scope(isolate1);
17049 v8::Local<v8::Context> context =
17050 v8::Local<v8::Context>::New(isolate1, context1);
17051 v8::Context::Scope context_scope(context);
17052 // Now again in isolate 1
17053 ExpectString("function f() { return foo; }; f()", "isolate 1");
17058 // Run some stuff in default isolate.
17059 v8::Persistent<v8::Context> context_default;
17061 v8::Isolate* isolate = CcTest::isolate();
17062 v8::Isolate::Scope iscope(isolate);
17063 v8::HandleScope scope(isolate);
17064 context_default.Reset(isolate, Context::New(isolate));
17068 v8::HandleScope scope(CcTest::isolate());
17069 v8::Local<v8::Context> context =
17070 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17071 v8::Context::Scope context_scope(context);
17072 // Variables in other isolates should be not available, verify there
17073 // is an exception.
17074 ExpectTrue("function f() {"
17082 "var isDefaultIsolate = true;"
17089 v8::Isolate::Scope iscope(isolate2);
17090 v8::HandleScope scope(isolate2);
17091 v8::Local<v8::Context> context =
17092 v8::Local<v8::Context>::New(isolate2, context2);
17093 v8::Context::Scope context_scope(context);
17094 ExpectString("function f() { return foo; }; f()", "isolate 2");
17098 v8::HandleScope scope(v8::Isolate::GetCurrent());
17099 v8::Local<v8::Context> context =
17100 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
17101 v8::Context::Scope context_scope(context);
17102 ExpectString("function f() { return foo; }; f()", "isolate 1");
17106 v8::Isolate::Scope iscope(isolate2);
17113 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17114 last_location = last_message = NULL;
17116 isolate1->Dispose();
17117 CHECK(!last_location);
17118 CHECK(!last_message);
17120 isolate2->Dispose();
17121 CHECK(!last_location);
17122 CHECK(!last_message);
17124 // Check that default isolate still runs.
17126 v8::HandleScope scope(CcTest::isolate());
17127 v8::Local<v8::Context> context =
17128 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17129 v8::Context::Scope context_scope(context);
17130 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
17135 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
17136 v8::Isolate::Scope isolate_scope(isolate);
17137 v8::HandleScope scope(isolate);
17138 LocalContext context(isolate);
17139 i::ScopedVector<char> code(1024);
17140 i::SNPrintF(code, "function fib(n) {"
17141 " if (n <= 2) return 1;"
17142 " return fib(n-1) + fib(n-2);"
17145 Local<Value> value = CompileRun(code.start());
17146 CHECK(value->IsNumber());
17147 return static_cast<int>(value->NumberValue());
17150 class IsolateThread : public v8::base::Thread {
17152 explicit IsolateThread(int fib_limit)
17153 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
17156 v8::Isolate::CreateParams create_params;
17157 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17158 v8::Isolate* isolate = v8::Isolate::New(create_params);
17159 result_ = CalcFibonacci(isolate, fib_limit_);
17160 isolate->Dispose();
17163 int result() { return result_; }
17171 TEST(MultipleIsolatesOnIndividualThreads) {
17172 IsolateThread thread1(21);
17173 IsolateThread thread2(12);
17175 // Compute some fibonacci numbers on 3 threads in 3 isolates.
17179 int result1 = CalcFibonacci(CcTest::isolate(), 21);
17180 int result2 = CalcFibonacci(CcTest::isolate(), 12);
17185 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
17186 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
17187 CHECK_EQ(result1, 10946);
17188 CHECK_EQ(result2, 144);
17189 CHECK_EQ(result1, thread1.result());
17190 CHECK_EQ(result2, thread2.result());
17194 TEST(IsolateDifferentContexts) {
17195 v8::Isolate::CreateParams create_params;
17196 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17197 v8::Isolate* isolate = v8::Isolate::New(create_params);
17198 Local<v8::Context> context;
17200 v8::Isolate::Scope isolate_scope(isolate);
17201 v8::HandleScope handle_scope(isolate);
17202 context = v8::Context::New(isolate);
17203 v8::Context::Scope context_scope(context);
17204 Local<Value> v = CompileRun("2");
17205 CHECK(v->IsNumber());
17206 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
17209 v8::Isolate::Scope isolate_scope(isolate);
17210 v8::HandleScope handle_scope(isolate);
17211 context = v8::Context::New(isolate);
17212 v8::Context::Scope context_scope(context);
17213 Local<Value> v = CompileRun("22");
17214 CHECK(v->IsNumber());
17215 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
17217 isolate->Dispose();
17220 class InitDefaultIsolateThread : public v8::base::Thread {
17223 SetResourceConstraints,
17225 SetCounterFunction,
17226 SetCreateHistogramFunction,
17227 SetAddHistogramSampleFunction
17230 explicit InitDefaultIsolateThread(TestCase testCase)
17231 : Thread(Options("InitDefaultIsolateThread")),
17232 testCase_(testCase),
17236 v8::Isolate::CreateParams create_params;
17237 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17238 switch (testCase_) {
17239 case SetResourceConstraints: {
17240 create_params.constraints.set_max_semi_space_size(1);
17241 create_params.constraints.set_max_old_space_size(4);
17247 v8::Isolate* isolate = v8::Isolate::New(create_params);
17249 switch (testCase_) {
17250 case SetResourceConstraints:
17251 // Already handled in pre-Isolate-creation block.
17254 case SetFatalHandler:
17255 v8::V8::SetFatalErrorHandler(NULL);
17258 case SetCounterFunction:
17259 CcTest::isolate()->SetCounterFunction(NULL);
17262 case SetCreateHistogramFunction:
17263 CcTest::isolate()->SetCreateHistogramFunction(NULL);
17266 case SetAddHistogramSampleFunction:
17267 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
17271 isolate->Dispose();
17275 bool result() { return result_; }
17278 TestCase testCase_;
17283 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
17284 InitDefaultIsolateThread thread(testCase);
17287 CHECK_EQ(thread.result(), true);
17291 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
17292 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
17296 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
17297 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
17301 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
17302 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
17306 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
17307 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
17311 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
17312 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
17316 TEST(StringCheckMultipleContexts) {
17318 "(function() { return \"a\".charAt(0); })()";
17321 // Run the code twice in the first context to initialize the call IC.
17322 LocalContext context1;
17323 v8::HandleScope scope(context1->GetIsolate());
17324 ExpectString(code, "a");
17325 ExpectString(code, "a");
17329 // Change the String.prototype in the second context and check
17330 // that the right function gets called.
17331 LocalContext context2;
17332 v8::HandleScope scope(context2->GetIsolate());
17333 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
17334 ExpectString(code, "not a");
17339 TEST(NumberCheckMultipleContexts) {
17341 "(function() { return (42).toString(); })()";
17344 // Run the code twice in the first context to initialize the call IC.
17345 LocalContext context1;
17346 v8::HandleScope scope(context1->GetIsolate());
17347 ExpectString(code, "42");
17348 ExpectString(code, "42");
17352 // Change the Number.prototype in the second context and check
17353 // that the right function gets called.
17354 LocalContext context2;
17355 v8::HandleScope scope(context2->GetIsolate());
17356 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
17357 ExpectString(code, "not 42");
17362 TEST(BooleanCheckMultipleContexts) {
17364 "(function() { return true.toString(); })()";
17367 // Run the code twice in the first context to initialize the call IC.
17368 LocalContext context1;
17369 v8::HandleScope scope(context1->GetIsolate());
17370 ExpectString(code, "true");
17371 ExpectString(code, "true");
17375 // Change the Boolean.prototype in the second context and check
17376 // that the right function gets called.
17377 LocalContext context2;
17378 v8::HandleScope scope(context2->GetIsolate());
17379 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
17380 ExpectString(code, "");
17385 TEST(DontDeleteCellLoadIC) {
17386 const char* function_code =
17387 "function readCell() { while (true) { return cell; } }";
17390 // Run the code twice in the first context to initialize the load
17391 // IC for a don't delete cell.
17392 LocalContext context1;
17393 v8::HandleScope scope(context1->GetIsolate());
17394 CompileRun("var cell = \"first\";");
17395 ExpectBoolean("delete cell", false);
17396 CompileRun(function_code);
17397 ExpectString("readCell()", "first");
17398 ExpectString("readCell()", "first");
17402 // Use a deletable cell in the second context.
17403 LocalContext context2;
17404 v8::HandleScope scope(context2->GetIsolate());
17405 CompileRun("cell = \"second\";");
17406 CompileRun(function_code);
17407 ExpectString("readCell()", "second");
17408 ExpectBoolean("delete cell", true);
17409 ExpectString("(function() {"
17411 " return readCell();"
17413 " return e.toString();"
17416 "ReferenceError: cell is not defined");
17417 CompileRun("cell = \"new_second\";");
17418 CcTest::heap()->CollectAllGarbage();
17419 ExpectString("readCell()", "new_second");
17420 ExpectString("readCell()", "new_second");
17425 class Visitor42 : public v8::PersistentHandleVisitor {
17427 explicit Visitor42(v8::Persistent<v8::Object>* object)
17428 : counter_(0), object_(object) { }
17430 virtual void VisitPersistentHandle(Persistent<Value>* value,
17431 uint16_t class_id) {
17432 if (class_id != 42) return;
17433 CHECK_EQ(42, value->WrapperClassId());
17434 v8::Isolate* isolate = CcTest::isolate();
17435 v8::HandleScope handle_scope(isolate);
17436 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
17437 v8::Handle<v8::Value> object =
17438 v8::Local<v8::Object>::New(isolate, *object_);
17439 CHECK(handle->IsObject());
17440 CHECK(Handle<Object>::Cast(handle)->Equals(object));
17445 v8::Persistent<v8::Object>* object_;
17449 TEST(PersistentHandleVisitor) {
17450 LocalContext context;
17451 v8::Isolate* isolate = context->GetIsolate();
17452 v8::HandleScope scope(isolate);
17453 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17454 CHECK_EQ(0, object.WrapperClassId());
17455 object.SetWrapperClassId(42);
17456 CHECK_EQ(42, object.WrapperClassId());
17458 Visitor42 visitor(&object);
17459 v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
17460 CHECK_EQ(1, visitor.counter_);
17466 TEST(WrapperClassId) {
17467 LocalContext context;
17468 v8::Isolate* isolate = context->GetIsolate();
17469 v8::HandleScope scope(isolate);
17470 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17471 CHECK_EQ(0, object.WrapperClassId());
17472 object.SetWrapperClassId(65535);
17473 CHECK_EQ(65535, object.WrapperClassId());
17478 TEST(PersistentHandleInNewSpaceVisitor) {
17479 LocalContext context;
17480 v8::Isolate* isolate = context->GetIsolate();
17481 v8::HandleScope scope(isolate);
17482 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
17483 CHECK_EQ(0, object1.WrapperClassId());
17484 object1.SetWrapperClassId(42);
17485 CHECK_EQ(42, object1.WrapperClassId());
17487 CcTest::heap()->CollectAllGarbage();
17488 CcTest::heap()->CollectAllGarbage();
17490 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
17491 CHECK_EQ(0, object2.WrapperClassId());
17492 object2.SetWrapperClassId(42);
17493 CHECK_EQ(42, object2.WrapperClassId());
17495 Visitor42 visitor(&object2);
17496 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
17497 CHECK_EQ(1, visitor.counter_);
17505 LocalContext context;
17506 v8::HandleScope scope(context->GetIsolate());
17508 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
17509 CHECK(re->IsRegExp());
17510 CHECK(re->GetSource()->Equals(v8_str("foo")));
17511 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
17513 re = v8::RegExp::New(v8_str("bar"),
17514 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
17515 v8::RegExp::kGlobal));
17516 CHECK(re->IsRegExp());
17517 CHECK(re->GetSource()->Equals(v8_str("bar")));
17518 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
17519 static_cast<int>(re->GetFlags()));
17521 re = v8::RegExp::New(v8_str("baz"),
17522 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
17523 v8::RegExp::kMultiline));
17524 CHECK(re->IsRegExp());
17525 CHECK(re->GetSource()->Equals(v8_str("baz")));
17526 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
17527 static_cast<int>(re->GetFlags()));
17529 re = CompileRun("/quux/").As<v8::RegExp>();
17530 CHECK(re->IsRegExp());
17531 CHECK(re->GetSource()->Equals(v8_str("quux")));
17532 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
17534 re = CompileRun("/quux/gm").As<v8::RegExp>();
17535 CHECK(re->IsRegExp());
17536 CHECK(re->GetSource()->Equals(v8_str("quux")));
17537 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
17538 static_cast<int>(re->GetFlags()));
17540 // Override the RegExp constructor and check the API constructor
17542 CompileRun("RegExp = function() {}");
17544 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
17545 CHECK(re->IsRegExp());
17546 CHECK(re->GetSource()->Equals(v8_str("foobar")));
17547 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
17549 re = v8::RegExp::New(v8_str("foobarbaz"),
17550 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
17551 v8::RegExp::kMultiline));
17552 CHECK(re->IsRegExp());
17553 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
17554 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
17555 static_cast<int>(re->GetFlags()));
17557 context->Global()->Set(v8_str("re"), re);
17558 ExpectTrue("re.test('FoobarbaZ')");
17560 // RegExps are objects on which you can set properties.
17561 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
17562 v8::Handle<v8::Value> value(CompileRun("re.property"));
17563 CHECK_EQ(32, value->Int32Value());
17565 v8::TryCatch try_catch(context->GetIsolate());
17566 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
17567 CHECK(re.IsEmpty());
17568 CHECK(try_catch.HasCaught());
17569 context->Global()->Set(v8_str("ex"), try_catch.Exception());
17570 ExpectTrue("ex instanceof SyntaxError");
17574 THREADED_TEST(Equals) {
17575 LocalContext localContext;
17576 v8::HandleScope handleScope(localContext->GetIsolate());
17578 v8::Handle<v8::Object> globalProxy = localContext->Global();
17579 v8::Handle<Value> global = globalProxy->GetPrototype();
17581 CHECK(global->StrictEquals(global));
17582 CHECK(!global->StrictEquals(globalProxy));
17583 CHECK(!globalProxy->StrictEquals(global));
17584 CHECK(globalProxy->StrictEquals(globalProxy));
17586 CHECK(global->Equals(global));
17587 CHECK(!global->Equals(globalProxy));
17588 CHECK(!globalProxy->Equals(global));
17589 CHECK(globalProxy->Equals(globalProxy));
17593 static void Getter(v8::Local<v8::Name> property,
17594 const v8::PropertyCallbackInfo<v8::Value>& info) {
17595 info.GetReturnValue().Set(v8_str("42!"));
17599 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
17600 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
17601 result->Set(0, v8_str("universalAnswer"));
17602 info.GetReturnValue().Set(result);
17606 TEST(NamedEnumeratorAndForIn) {
17607 LocalContext context;
17608 v8::Isolate* isolate = context->GetIsolate();
17609 v8::HandleScope handle_scope(isolate);
17610 v8::Context::Scope context_scope(context.local());
17612 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
17613 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
17614 NULL, Enumerator));
17615 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
17616 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
17617 "var result = []; for (var k in o) result.push(k); result"));
17618 CHECK_EQ(1u, result->Length());
17619 CHECK(v8_str("universalAnswer")->Equals(result->Get(0)));
17623 TEST(DefinePropertyPostDetach) {
17624 LocalContext context;
17625 v8::HandleScope scope(context->GetIsolate());
17626 v8::Handle<v8::Object> proxy = context->Global();
17627 v8::Handle<v8::Function> define_property =
17628 CompileRun("(function() {"
17629 " Object.defineProperty("
17632 " { configurable: true, enumerable: true, value: 3 });"
17633 "})").As<Function>();
17634 context->DetachGlobal();
17635 define_property->Call(proxy, 0, NULL);
17639 static void InstallContextId(v8::Handle<Context> context, int id) {
17640 Context::Scope scope(context);
17641 CompileRun("Object.prototype").As<Object>()->
17642 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
17646 static void CheckContextId(v8::Handle<Object> object, int expected) {
17647 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
17651 THREADED_TEST(CreationContext) {
17652 v8::Isolate* isolate = CcTest::isolate();
17653 HandleScope handle_scope(isolate);
17654 Handle<Context> context1 = Context::New(isolate);
17655 InstallContextId(context1, 1);
17656 Handle<Context> context2 = Context::New(isolate);
17657 InstallContextId(context2, 2);
17658 Handle<Context> context3 = Context::New(isolate);
17659 InstallContextId(context3, 3);
17661 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
17663 Local<Object> object1;
17664 Local<Function> func1;
17666 Context::Scope scope(context1);
17667 object1 = Object::New(isolate);
17668 func1 = tmpl->GetFunction();
17671 Local<Object> object2;
17672 Local<Function> func2;
17674 Context::Scope scope(context2);
17675 object2 = Object::New(isolate);
17676 func2 = tmpl->GetFunction();
17679 Local<Object> instance1;
17680 Local<Object> instance2;
17683 Context::Scope scope(context3);
17684 instance1 = func1->NewInstance();
17685 instance2 = func2->NewInstance();
17689 Handle<Context> other_context = Context::New(isolate);
17690 Context::Scope scope(other_context);
17691 CHECK(object1->CreationContext() == context1);
17692 CheckContextId(object1, 1);
17693 CHECK(func1->CreationContext() == context1);
17694 CheckContextId(func1, 1);
17695 CHECK(instance1->CreationContext() == context1);
17696 CheckContextId(instance1, 1);
17697 CHECK(object2->CreationContext() == context2);
17698 CheckContextId(object2, 2);
17699 CHECK(func2->CreationContext() == context2);
17700 CheckContextId(func2, 2);
17701 CHECK(instance2->CreationContext() == context2);
17702 CheckContextId(instance2, 2);
17706 Context::Scope scope(context1);
17707 CHECK(object1->CreationContext() == context1);
17708 CheckContextId(object1, 1);
17709 CHECK(func1->CreationContext() == context1);
17710 CheckContextId(func1, 1);
17711 CHECK(instance1->CreationContext() == context1);
17712 CheckContextId(instance1, 1);
17713 CHECK(object2->CreationContext() == context2);
17714 CheckContextId(object2, 2);
17715 CHECK(func2->CreationContext() == context2);
17716 CheckContextId(func2, 2);
17717 CHECK(instance2->CreationContext() == context2);
17718 CheckContextId(instance2, 2);
17722 Context::Scope scope(context2);
17723 CHECK(object1->CreationContext() == context1);
17724 CheckContextId(object1, 1);
17725 CHECK(func1->CreationContext() == context1);
17726 CheckContextId(func1, 1);
17727 CHECK(instance1->CreationContext() == context1);
17728 CheckContextId(instance1, 1);
17729 CHECK(object2->CreationContext() == context2);
17730 CheckContextId(object2, 2);
17731 CHECK(func2->CreationContext() == context2);
17732 CheckContextId(func2, 2);
17733 CHECK(instance2->CreationContext() == context2);
17734 CheckContextId(instance2, 2);
17739 THREADED_TEST(CreationContextOfJsFunction) {
17740 HandleScope handle_scope(CcTest::isolate());
17741 Handle<Context> context = Context::New(CcTest::isolate());
17742 InstallContextId(context, 1);
17744 Local<Object> function;
17746 Context::Scope scope(context);
17747 function = CompileRun("function foo() {}; foo").As<Object>();
17750 Handle<Context> other_context = Context::New(CcTest::isolate());
17751 Context::Scope scope(other_context);
17752 CHECK(function->CreationContext() == context);
17753 CheckContextId(function, 1);
17757 void HasOwnPropertyIndexedPropertyGetter(
17759 const v8::PropertyCallbackInfo<v8::Value>& info) {
17760 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
17764 void HasOwnPropertyNamedPropertyGetter(
17765 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
17766 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
17770 void HasOwnPropertyIndexedPropertyQuery(
17771 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
17772 if (index == 42) info.GetReturnValue().Set(1);
17776 void HasOwnPropertyNamedPropertyQuery(
17777 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
17778 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
17782 void HasOwnPropertyNamedPropertyQuery2(
17783 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
17784 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
17788 void HasOwnPropertyAccessorGetter(
17789 Local<String> property,
17790 const v8::PropertyCallbackInfo<v8::Value>& info) {
17791 info.GetReturnValue().Set(v8_str("yes"));
17795 TEST(HasOwnProperty) {
17797 v8::Isolate* isolate = env->GetIsolate();
17798 v8::HandleScope scope(isolate);
17799 { // Check normal properties and defined getters.
17800 Handle<Value> value = CompileRun(
17803 " this.__defineGetter__('baz', function() { return 1; });"
17805 "function Bar() { "
17807 " this.__defineGetter__('bla', function() { return 2; });"
17809 "Bar.prototype = new Foo();"
17811 CHECK(value->IsObject());
17812 Handle<Object> object = value->ToObject(isolate);
17813 CHECK(object->Has(v8_str("foo")));
17814 CHECK(!object->HasOwnProperty(v8_str("foo")));
17815 CHECK(object->HasOwnProperty(v8_str("bar")));
17816 CHECK(object->Has(v8_str("baz")));
17817 CHECK(!object->HasOwnProperty(v8_str("baz")));
17818 CHECK(object->HasOwnProperty(v8_str("bla")));
17820 { // Check named getter interceptors.
17821 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17822 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
17823 HasOwnPropertyNamedPropertyGetter));
17824 Handle<Object> instance = templ->NewInstance();
17825 CHECK(!instance->HasOwnProperty(v8_str("42")));
17826 CHECK(instance->HasOwnProperty(v8_str("foo")));
17827 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17829 { // Check indexed getter interceptors.
17830 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17831 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
17832 HasOwnPropertyIndexedPropertyGetter));
17833 Handle<Object> instance = templ->NewInstance();
17834 CHECK(instance->HasOwnProperty(v8_str("42")));
17835 CHECK(!instance->HasOwnProperty(v8_str("43")));
17836 CHECK(!instance->HasOwnProperty(v8_str("foo")));
17838 { // Check named query interceptors.
17839 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17840 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
17841 0, 0, HasOwnPropertyNamedPropertyQuery));
17842 Handle<Object> instance = templ->NewInstance();
17843 CHECK(instance->HasOwnProperty(v8_str("foo")));
17844 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17846 { // Check indexed query interceptors.
17847 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17848 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
17849 0, 0, HasOwnPropertyIndexedPropertyQuery));
17850 Handle<Object> instance = templ->NewInstance();
17851 CHECK(instance->HasOwnProperty(v8_str("42")));
17852 CHECK(!instance->HasOwnProperty(v8_str("41")));
17854 { // Check callbacks.
17855 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17856 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
17857 Handle<Object> instance = templ->NewInstance();
17858 CHECK(instance->HasOwnProperty(v8_str("foo")));
17859 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17861 { // Check that query wins on disagreement.
17862 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17863 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
17864 HasOwnPropertyNamedPropertyGetter, 0,
17865 HasOwnPropertyNamedPropertyQuery2));
17866 Handle<Object> instance = templ->NewInstance();
17867 CHECK(!instance->HasOwnProperty(v8_str("foo")));
17868 CHECK(instance->HasOwnProperty(v8_str("bar")));
17873 TEST(IndexedInterceptorWithStringProto) {
17874 v8::Isolate* isolate = CcTest::isolate();
17875 v8::HandleScope scope(isolate);
17876 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17877 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
17878 NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
17879 LocalContext context;
17880 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17881 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
17882 // These should be intercepted.
17883 CHECK(CompileRun("42 in obj")->BooleanValue());
17884 CHECK(CompileRun("'42' in obj")->BooleanValue());
17885 // These should fall through to the String prototype.
17886 CHECK(CompileRun("0 in obj")->BooleanValue());
17887 CHECK(CompileRun("'0' in obj")->BooleanValue());
17888 // And these should both fail.
17889 CHECK(!CompileRun("32 in obj")->BooleanValue());
17890 CHECK(!CompileRun("'32' in obj")->BooleanValue());
17894 void CheckCodeGenerationAllowed() {
17895 Handle<Value> result = CompileRun("eval('42')");
17896 CHECK_EQ(42, result->Int32Value());
17897 result = CompileRun("(function(e) { return e('42'); })(eval)");
17898 CHECK_EQ(42, result->Int32Value());
17899 result = CompileRun("var f = new Function('return 42'); f()");
17900 CHECK_EQ(42, result->Int32Value());
17904 void CheckCodeGenerationDisallowed() {
17905 TryCatch try_catch(CcTest::isolate());
17907 Handle<Value> result = CompileRun("eval('42')");
17908 CHECK(result.IsEmpty());
17909 CHECK(try_catch.HasCaught());
17912 result = CompileRun("(function(e) { return e('42'); })(eval)");
17913 CHECK(result.IsEmpty());
17914 CHECK(try_catch.HasCaught());
17917 result = CompileRun("var f = new Function('return 42'); f()");
17918 CHECK(result.IsEmpty());
17919 CHECK(try_catch.HasCaught());
17923 bool CodeGenerationAllowed(Local<Context> context) {
17924 ApiTestFuzzer::Fuzz();
17929 bool CodeGenerationDisallowed(Local<Context> context) {
17930 ApiTestFuzzer::Fuzz();
17935 THREADED_TEST(AllowCodeGenFromStrings) {
17936 LocalContext context;
17937 v8::HandleScope scope(context->GetIsolate());
17939 // eval and the Function constructor allowed by default.
17940 CHECK(context->IsCodeGenerationFromStringsAllowed());
17941 CheckCodeGenerationAllowed();
17943 // Disallow eval and the Function constructor.
17944 context->AllowCodeGenerationFromStrings(false);
17945 CHECK(!context->IsCodeGenerationFromStringsAllowed());
17946 CheckCodeGenerationDisallowed();
17949 context->AllowCodeGenerationFromStrings(true);
17950 CheckCodeGenerationAllowed();
17952 // Disallow but setting a global callback that will allow the calls.
17953 context->AllowCodeGenerationFromStrings(false);
17954 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
17955 CHECK(!context->IsCodeGenerationFromStringsAllowed());
17956 CheckCodeGenerationAllowed();
17958 // Set a callback that disallows the code generation.
17959 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
17960 CHECK(!context->IsCodeGenerationFromStringsAllowed());
17961 CheckCodeGenerationDisallowed();
17965 TEST(SetErrorMessageForCodeGenFromStrings) {
17966 LocalContext context;
17967 v8::HandleScope scope(context->GetIsolate());
17968 TryCatch try_catch(context->GetIsolate());
17970 Handle<String> message = v8_str("Message") ;
17971 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
17972 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
17973 context->AllowCodeGenerationFromStrings(false);
17974 context->SetErrorMessageForCodeGenerationFromStrings(message);
17975 Handle<Value> result = CompileRun("eval('42')");
17976 CHECK(result.IsEmpty());
17977 CHECK(try_catch.HasCaught());
17978 Handle<String> actual_message = try_catch.Message()->Get();
17979 CHECK(expected_message->Equals(actual_message));
17983 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
17987 THREADED_TEST(CallAPIFunctionOnNonObject) {
17988 LocalContext context;
17989 v8::Isolate* isolate = context->GetIsolate();
17990 v8::HandleScope scope(isolate);
17991 Handle<FunctionTemplate> templ =
17992 v8::FunctionTemplate::New(isolate, NonObjectThis);
17993 Handle<Function> function = templ->GetFunction();
17994 context->Global()->Set(v8_str("f"), function);
17995 TryCatch try_catch(isolate);
17996 CompileRun("f.call(2)");
18000 // Regression test for issue 1470.
18001 THREADED_TEST(ReadOnlyIndexedProperties) {
18002 v8::Isolate* isolate = CcTest::isolate();
18003 v8::HandleScope scope(isolate);
18004 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18006 LocalContext context;
18007 Local<v8::Object> obj = templ->NewInstance();
18008 context->Global()->Set(v8_str("obj"), obj);
18009 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18010 obj->Set(v8_str("1"), v8_str("foobar"));
18011 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("1"))));
18012 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
18013 obj->Set(v8_num(2), v8_str("foobar"));
18014 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_num(2))));
18016 // Test non-smi case.
18017 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18018 obj->Set(v8_str("2000000000"), v8_str("foobar"));
18019 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("2000000000"))));
18023 static int CountLiveMapsInMapCache(i::Context* context) {
18024 i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
18025 int length = map_cache->length();
18027 for (int i = 0; i < length; i++) {
18028 i::Object* value = map_cache->get(i);
18029 if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
18035 THREADED_TEST(Regress1516) {
18036 LocalContext context;
18037 v8::HandleScope scope(context->GetIsolate());
18039 // Object with 20 properties is not a common case, so it should be removed
18040 // from the cache after GC.
18041 { v8::HandleScope temp_scope(context->GetIsolate());
18044 "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
18045 "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
18046 "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
18047 "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
18051 int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
18052 CHECK_LE(1, elements);
18054 CcTest::heap()->CollectAllGarbage();
18056 CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
18060 THREADED_TEST(Regress93759) {
18061 v8::Isolate* isolate = CcTest::isolate();
18062 HandleScope scope(isolate);
18064 // Template for object with security check.
18065 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
18066 no_proto_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
18068 // Templates for objects with hidden prototypes and possibly security check.
18069 Local<FunctionTemplate> hidden_proto_template =
18070 v8::FunctionTemplate::New(isolate);
18071 hidden_proto_template->SetHiddenPrototype(true);
18073 Local<FunctionTemplate> protected_hidden_proto_template =
18074 v8::FunctionTemplate::New(isolate);
18075 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
18076 AccessAlwaysBlocked, NULL);
18077 protected_hidden_proto_template->SetHiddenPrototype(true);
18079 // Context for "foreign" objects used in test.
18080 Local<Context> context = v8::Context::New(isolate);
18083 // Plain object, no security check.
18084 Local<Object> simple_object = Object::New(isolate);
18086 // Object with explicit security check.
18087 Local<Object> protected_object = no_proto_template->NewInstance();
18089 // JSGlobalProxy object, always have security check.
18090 Local<Object> proxy_object = context->Global();
18092 // Global object, the prototype of proxy_object. No security checks.
18093 Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
18095 // Hidden prototype without security check.
18096 Local<Object> hidden_prototype =
18097 hidden_proto_template->GetFunction()->NewInstance();
18098 Local<Object> object_with_hidden =
18099 Object::New(isolate);
18100 object_with_hidden->SetPrototype(hidden_prototype);
18102 // Hidden prototype with security check on the hidden prototype.
18103 Local<Object> protected_hidden_prototype =
18104 protected_hidden_proto_template->GetFunction()->NewInstance();
18105 Local<Object> object_with_protected_hidden =
18106 Object::New(isolate);
18107 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
18111 // Template for object for second context. Values to test are put on it as
18113 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
18114 global_template->Set(v8_str("simple"), simple_object);
18115 global_template->Set(v8_str("protected"), protected_object);
18116 global_template->Set(v8_str("global"), global_object);
18117 global_template->Set(v8_str("proxy"), proxy_object);
18118 global_template->Set(v8_str("hidden"), object_with_hidden);
18119 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
18121 LocalContext context2(NULL, global_template);
18123 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
18124 CHECK(result1->Equals(simple_object->GetPrototype()));
18126 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
18127 CHECK(result2.IsEmpty());
18129 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
18130 CHECK(result3->Equals(global_object->GetPrototype()));
18132 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
18133 CHECK(result4.IsEmpty());
18135 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
18136 CHECK(result5->Equals(
18137 object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
18139 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
18140 CHECK(result6.IsEmpty());
18144 static void TestReceiver(Local<Value> expected_result,
18145 Local<Value> expected_receiver,
18146 const char* code) {
18147 Local<Value> result = CompileRun(code);
18148 CHECK(result->IsObject());
18149 CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
18150 CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
18154 THREADED_TEST(ForeignFunctionReceiver) {
18155 v8::Isolate* isolate = CcTest::isolate();
18156 HandleScope scope(isolate);
18158 // Create two contexts with different "id" properties ('i' and 'o').
18159 // Call a function both from its own context and from a the foreign
18160 // context, and see what "this" is bound to (returning both "this"
18161 // and "this.id" for comparison).
18163 Local<Context> foreign_context = v8::Context::New(isolate);
18164 foreign_context->Enter();
18165 Local<Value> foreign_function =
18166 CompileRun("function func() { return { 0: this.id, "
18168 " toString: function() { "
18175 CHECK(foreign_function->IsFunction());
18176 foreign_context->Exit();
18178 LocalContext context;
18180 Local<String> password = v8_str("Password");
18181 // Don't get hit by security checks when accessing foreign_context's
18182 // global receiver (aka. global proxy).
18183 context->SetSecurityToken(password);
18184 foreign_context->SetSecurityToken(password);
18186 Local<String> i = v8_str("i");
18187 Local<String> o = v8_str("o");
18188 Local<String> id = v8_str("id");
18190 CompileRun("function ownfunc() { return { 0: this.id, "
18192 " toString: function() { "
18199 context->Global()->Set(v8_str("func"), foreign_function);
18201 // Sanity check the contexts.
18202 CHECK(i->Equals(foreign_context->Global()->Get(id)));
18203 CHECK(o->Equals(context->Global()->Get(id)));
18205 // Checking local function's receiver.
18206 // Calling function using its call/apply methods.
18207 TestReceiver(o, context->Global(), "ownfunc.call()");
18208 TestReceiver(o, context->Global(), "ownfunc.apply()");
18209 // Making calls through built-in functions.
18210 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
18211 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
18212 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
18213 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
18214 // Calling with environment record as base.
18215 TestReceiver(o, context->Global(), "ownfunc()");
18216 // Calling with no base.
18217 TestReceiver(o, context->Global(), "(1,ownfunc)()");
18219 // Checking foreign function return value.
18220 // Calling function using its call/apply methods.
18221 TestReceiver(i, foreign_context->Global(), "func.call()");
18222 TestReceiver(i, foreign_context->Global(), "func.apply()");
18223 // Calling function using another context's call/apply methods.
18224 TestReceiver(i, foreign_context->Global(),
18225 "Function.prototype.call.call(func)");
18226 TestReceiver(i, foreign_context->Global(),
18227 "Function.prototype.call.apply(func)");
18228 TestReceiver(i, foreign_context->Global(),
18229 "Function.prototype.apply.call(func)");
18230 TestReceiver(i, foreign_context->Global(),
18231 "Function.prototype.apply.apply(func)");
18232 // Making calls through built-in functions.
18233 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
18234 // ToString(func()) is func()[0], i.e., the returned this.id.
18235 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
18236 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
18237 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
18239 // Calling with environment record as base.
18240 TestReceiver(i, foreign_context->Global(), "func()");
18241 // Calling with no base.
18242 TestReceiver(i, foreign_context->Global(), "(1,func)()");
18246 uint8_t callback_fired = 0;
18249 void CallCompletedCallback1() {
18250 v8::base::OS::Print("Firing callback 1.\n");
18251 callback_fired ^= 1; // Toggle first bit.
18255 void CallCompletedCallback2() {
18256 v8::base::OS::Print("Firing callback 2.\n");
18257 callback_fired ^= 2; // Toggle second bit.
18261 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
18262 int32_t level = args[0]->Int32Value();
18265 v8::base::OS::Print("Entering recursion level %d.\n", level);
18267 i::Vector<char> script_vector(script, sizeof(script));
18268 i::SNPrintF(script_vector, "recursion(%d)", level);
18269 CompileRun(script_vector.start());
18270 v8::base::OS::Print("Leaving recursion level %d.\n", level);
18271 CHECK_EQ(0, callback_fired);
18273 v8::base::OS::Print("Recursion ends.\n");
18274 CHECK_EQ(0, callback_fired);
18279 TEST(CallCompletedCallback) {
18281 v8::HandleScope scope(env->GetIsolate());
18282 v8::Handle<v8::FunctionTemplate> recursive_runtime =
18283 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
18284 env->Global()->Set(v8_str("recursion"),
18285 recursive_runtime->GetFunction());
18286 // Adding the same callback a second time has no effect.
18287 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18288 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18289 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
18290 v8::base::OS::Print("--- Script (1) ---\n");
18291 Local<Script> script = v8::Script::Compile(
18292 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
18294 CHECK_EQ(3, callback_fired);
18296 v8::base::OS::Print("\n--- Script (2) ---\n");
18297 callback_fired = 0;
18298 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
18300 CHECK_EQ(2, callback_fired);
18302 v8::base::OS::Print("\n--- Function ---\n");
18303 callback_fired = 0;
18304 Local<Function> recursive_function =
18305 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
18306 v8::Handle<Value> args[] = { v8_num(0) };
18307 recursive_function->Call(env->Global(), 1, args);
18308 CHECK_EQ(2, callback_fired);
18312 void CallCompletedCallbackNoException() {
18313 v8::HandleScope scope(CcTest::isolate());
18314 CompileRun("1+1;");
18318 void CallCompletedCallbackException() {
18319 v8::HandleScope scope(CcTest::isolate());
18320 CompileRun("throw 'second exception';");
18324 TEST(CallCompletedCallbackOneException) {
18326 v8::HandleScope scope(env->GetIsolate());
18327 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
18328 CompileRun("throw 'exception';");
18332 TEST(CallCompletedCallbackTwoExceptions) {
18334 v8::HandleScope scope(env->GetIsolate());
18335 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
18336 CompileRun("throw 'first exception';");
18340 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
18341 v8::HandleScope scope(info.GetIsolate());
18342 CompileRun("ext1Calls++;");
18346 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
18347 v8::HandleScope scope(info.GetIsolate());
18348 CompileRun("ext2Calls++;");
18352 void* g_passed_to_three = NULL;
18355 static void MicrotaskThree(void* data) {
18356 g_passed_to_three = data;
18360 TEST(EnqueueMicrotask) {
18362 v8::HandleScope scope(env->GetIsolate());
18364 "var ext1Calls = 0;"
18365 "var ext2Calls = 0;");
18366 CompileRun("1+1;");
18367 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18368 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18370 env->GetIsolate()->EnqueueMicrotask(
18371 Function::New(env->GetIsolate(), MicrotaskOne));
18372 CompileRun("1+1;");
18373 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18374 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18376 env->GetIsolate()->EnqueueMicrotask(
18377 Function::New(env->GetIsolate(), MicrotaskOne));
18378 env->GetIsolate()->EnqueueMicrotask(
18379 Function::New(env->GetIsolate(), MicrotaskTwo));
18380 CompileRun("1+1;");
18381 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18382 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18384 env->GetIsolate()->EnqueueMicrotask(
18385 Function::New(env->GetIsolate(), MicrotaskTwo));
18386 CompileRun("1+1;");
18387 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18388 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18390 CompileRun("1+1;");
18391 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18392 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18394 g_passed_to_three = NULL;
18395 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
18396 CompileRun("1+1;");
18397 CHECK(!g_passed_to_three);
18398 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18399 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18402 env->GetIsolate()->EnqueueMicrotask(
18403 Function::New(env->GetIsolate(), MicrotaskOne));
18404 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
18405 env->GetIsolate()->EnqueueMicrotask(
18406 Function::New(env->GetIsolate(), MicrotaskTwo));
18407 CompileRun("1+1;");
18408 CHECK_EQ(&dummy, g_passed_to_three);
18409 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
18410 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18411 g_passed_to_three = NULL;
18415 static void MicrotaskExceptionOne(
18416 const v8::FunctionCallbackInfo<Value>& info) {
18417 v8::HandleScope scope(info.GetIsolate());
18418 CompileRun("exception1Calls++;");
18419 info.GetIsolate()->ThrowException(
18420 v8::Exception::Error(v8_str("first")));
18424 static void MicrotaskExceptionTwo(
18425 const v8::FunctionCallbackInfo<Value>& info) {
18426 v8::HandleScope scope(info.GetIsolate());
18427 CompileRun("exception2Calls++;");
18428 info.GetIsolate()->ThrowException(
18429 v8::Exception::Error(v8_str("second")));
18433 TEST(RunMicrotasksIgnoresThrownExceptions) {
18435 v8::Isolate* isolate = env->GetIsolate();
18436 v8::HandleScope scope(isolate);
18438 "var exception1Calls = 0;"
18439 "var exception2Calls = 0;");
18440 isolate->EnqueueMicrotask(
18441 Function::New(isolate, MicrotaskExceptionOne));
18442 isolate->EnqueueMicrotask(
18443 Function::New(isolate, MicrotaskExceptionTwo));
18444 TryCatch try_catch(isolate);
18445 CompileRun("1+1;");
18446 CHECK(!try_catch.HasCaught());
18447 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
18448 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
18452 TEST(SetAutorunMicrotasks) {
18454 v8::HandleScope scope(env->GetIsolate());
18456 "var ext1Calls = 0;"
18457 "var ext2Calls = 0;");
18458 CompileRun("1+1;");
18459 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18460 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18462 env->GetIsolate()->EnqueueMicrotask(
18463 Function::New(env->GetIsolate(), MicrotaskOne));
18464 CompileRun("1+1;");
18465 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18466 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18468 env->GetIsolate()->SetAutorunMicrotasks(false);
18469 env->GetIsolate()->EnqueueMicrotask(
18470 Function::New(env->GetIsolate(), MicrotaskOne));
18471 env->GetIsolate()->EnqueueMicrotask(
18472 Function::New(env->GetIsolate(), MicrotaskTwo));
18473 CompileRun("1+1;");
18474 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18475 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18477 env->GetIsolate()->RunMicrotasks();
18478 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18479 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18481 env->GetIsolate()->EnqueueMicrotask(
18482 Function::New(env->GetIsolate(), MicrotaskTwo));
18483 CompileRun("1+1;");
18484 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18485 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18487 env->GetIsolate()->RunMicrotasks();
18488 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18489 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18491 env->GetIsolate()->SetAutorunMicrotasks(true);
18492 env->GetIsolate()->EnqueueMicrotask(
18493 Function::New(env->GetIsolate(), MicrotaskTwo));
18494 CompileRun("1+1;");
18495 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18496 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18498 env->GetIsolate()->EnqueueMicrotask(
18499 Function::New(env->GetIsolate(), MicrotaskTwo));
18501 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
18502 CompileRun("1+1;");
18503 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18504 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18507 CompileRun("1+1;");
18508 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18509 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
18513 TEST(RunMicrotasksWithoutEnteringContext) {
18514 v8::Isolate* isolate = CcTest::isolate();
18515 HandleScope handle_scope(isolate);
18516 isolate->SetAutorunMicrotasks(false);
18517 Handle<Context> context = Context::New(isolate);
18519 Context::Scope context_scope(context);
18520 CompileRun("var ext1Calls = 0;");
18521 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
18523 isolate->RunMicrotasks();
18525 Context::Scope context_scope(context);
18526 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18528 isolate->SetAutorunMicrotasks(true);
18532 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
18533 v8::DebugEvent event = event_details.GetEvent();
18534 if (event != v8::Break) return;
18535 Handle<Object> exec_state = event_details.GetExecutionState();
18536 Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
18537 CompileRun("function f(id) { new FrameDetails(id, 0); }");
18538 Handle<Function> fun =
18539 Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
18540 fun->Call(CcTest::global(), 1, &break_id);
18544 TEST(Regress385349) {
18545 i::FLAG_allow_natives_syntax = true;
18546 v8::Isolate* isolate = CcTest::isolate();
18547 HandleScope handle_scope(isolate);
18548 isolate->SetAutorunMicrotasks(false);
18549 Handle<Context> context = Context::New(isolate);
18550 v8::Debug::SetDebugEventListener(DebugEventInObserver);
18552 Context::Scope context_scope(context);
18553 CompileRun("var obj = {};"
18554 "Object.observe(obj, function(changes) { debugger; });"
18557 isolate->RunMicrotasks();
18558 isolate->SetAutorunMicrotasks(true);
18559 v8::Debug::SetDebugEventListener(NULL);
18563 #ifdef ENABLE_DISASSEMBLER
18564 static int probes_counter = 0;
18565 static int misses_counter = 0;
18566 static int updates_counter = 0;
18569 static int* LookupCounter(const char* name) {
18570 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
18571 return &probes_counter;
18572 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
18573 return &misses_counter;
18574 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
18575 return &updates_counter;
18581 static const char* kMegamorphicTestProgram =
18582 "function ClassA() { };"
18583 "function ClassB() { };"
18584 "ClassA.prototype.foo = function() { };"
18585 "ClassB.prototype.foo = function() { };"
18586 "function fooify(obj) { obj.foo(); };"
18587 "var a = new ClassA();"
18588 "var b = new ClassB();"
18589 "for (var i = 0; i < 10000; i++) {"
18596 static void StubCacheHelper(bool primary) {
18597 #ifdef ENABLE_DISASSEMBLER
18598 i::FLAG_native_code_counters = true;
18600 i::FLAG_test_primary_stub_cache = true;
18602 i::FLAG_test_secondary_stub_cache = true;
18604 i::FLAG_crankshaft = false;
18606 env->GetIsolate()->SetCounterFunction(LookupCounter);
18607 v8::HandleScope scope(env->GetIsolate());
18608 int initial_probes = probes_counter;
18609 int initial_misses = misses_counter;
18610 int initial_updates = updates_counter;
18611 CompileRun(kMegamorphicTestProgram);
18612 int probes = probes_counter - initial_probes;
18613 int misses = misses_counter - initial_misses;
18614 int updates = updates_counter - initial_updates;
18615 CHECK_LT(updates, 10);
18616 CHECK_LT(misses, 10);
18617 // TODO(verwaest): Update this test to overflow the degree of polymorphism
18618 // before megamorphism. The number of probes will only work once we teach the
18619 // serializer to embed references to counters in the stubs, given that the
18620 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
18621 CHECK_GE(probes, 0);
18626 TEST(SecondaryStubCache) {
18627 StubCacheHelper(true);
18631 TEST(PrimaryStubCache) {
18632 StubCacheHelper(false);
18637 static int cow_arrays_created_runtime = 0;
18640 static int* LookupCounterCOWArrays(const char* name) {
18641 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
18642 return &cow_arrays_created_runtime;
18649 TEST(CheckCOWArraysCreatedRuntimeCounter) {
18651 i::FLAG_native_code_counters = true;
18653 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
18654 v8::HandleScope scope(env->GetIsolate());
18655 int initial_cow_arrays = cow_arrays_created_runtime;
18656 CompileRun("var o = [1, 2, 3];");
18657 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
18658 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
18659 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
18660 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
18661 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
18666 TEST(StaticGetters) {
18667 LocalContext context;
18668 i::Factory* factory = CcTest::i_isolate()->factory();
18669 v8::Isolate* isolate = CcTest::isolate();
18670 v8::HandleScope scope(isolate);
18671 i::Handle<i::Object> undefined_value = factory->undefined_value();
18672 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
18673 i::Handle<i::Object> null_value = factory->null_value();
18674 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
18675 i::Handle<i::Object> true_value = factory->true_value();
18676 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
18677 i::Handle<i::Object> false_value = factory->false_value();
18678 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
18682 UNINITIALIZED_TEST(IsolateEmbedderData) {
18683 CcTest::DisableAutomaticDispose();
18684 v8::Isolate::CreateParams create_params;
18685 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18686 v8::Isolate* isolate = v8::Isolate::New(create_params);
18688 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
18689 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18690 CHECK(!isolate->GetData(slot));
18691 CHECK(!i_isolate->GetData(slot));
18693 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18694 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
18695 isolate->SetData(slot, data);
18697 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18698 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
18699 CHECK_EQ(data, isolate->GetData(slot));
18700 CHECK_EQ(data, i_isolate->GetData(slot));
18702 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18703 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
18704 isolate->SetData(slot, data);
18706 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18707 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
18708 CHECK_EQ(data, isolate->GetData(slot));
18709 CHECK_EQ(data, i_isolate->GetData(slot));
18712 isolate->Dispose();
18716 TEST(StringEmpty) {
18717 LocalContext context;
18718 i::Factory* factory = CcTest::i_isolate()->factory();
18719 v8::Isolate* isolate = CcTest::isolate();
18720 v8::HandleScope scope(isolate);
18721 i::Handle<i::Object> empty_string = factory->empty_string();
18722 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
18726 static int instance_checked_getter_count = 0;
18727 static void InstanceCheckedGetter(
18728 Local<String> name,
18729 const v8::PropertyCallbackInfo<v8::Value>& info) {
18730 CHECK(name->Equals(v8_str("foo")));
18731 instance_checked_getter_count++;
18732 info.GetReturnValue().Set(v8_num(11));
18736 static int instance_checked_setter_count = 0;
18737 static void InstanceCheckedSetter(Local<String> name,
18738 Local<Value> value,
18739 const v8::PropertyCallbackInfo<void>& info) {
18740 CHECK(name->Equals(v8_str("foo")));
18741 CHECK(value->Equals(v8_num(23)));
18742 instance_checked_setter_count++;
18746 static void CheckInstanceCheckedResult(int getters, int setters,
18747 bool expects_callbacks,
18748 TryCatch* try_catch) {
18749 if (expects_callbacks) {
18750 CHECK(!try_catch->HasCaught());
18751 CHECK_EQ(getters, instance_checked_getter_count);
18752 CHECK_EQ(setters, instance_checked_setter_count);
18754 CHECK(try_catch->HasCaught());
18755 CHECK_EQ(0, instance_checked_getter_count);
18756 CHECK_EQ(0, instance_checked_setter_count);
18758 try_catch->Reset();
18762 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
18763 instance_checked_getter_count = 0;
18764 instance_checked_setter_count = 0;
18765 TryCatch try_catch(CcTest::isolate());
18767 // Test path through generic runtime code.
18768 CompileRun("obj.foo");
18769 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
18770 CompileRun("obj.foo = 23");
18771 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
18773 // Test path through generated LoadIC and StoredIC.
18774 CompileRun("function test_get(o) { o.foo; }"
18776 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
18777 CompileRun("test_get(obj);");
18778 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
18779 CompileRun("test_get(obj);");
18780 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
18781 CompileRun("function test_set(o) { o.foo = 23; }"
18783 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
18784 CompileRun("test_set(obj);");
18785 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
18786 CompileRun("test_set(obj);");
18787 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
18789 // Test path through optimized code.
18790 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
18792 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
18793 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
18795 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
18797 // Cleanup so that closures start out fresh in next check.
18798 CompileRun("%DeoptimizeFunction(test_get);"
18799 "%ClearFunctionTypeFeedback(test_get);"
18800 "%DeoptimizeFunction(test_set);"
18801 "%ClearFunctionTypeFeedback(test_set);");
18805 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
18806 v8::internal::FLAG_allow_natives_syntax = true;
18807 LocalContext context;
18808 v8::HandleScope scope(context->GetIsolate());
18810 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
18811 Local<ObjectTemplate> inst = templ->InstanceTemplate();
18812 inst->SetAccessor(v8_str("foo"),
18813 InstanceCheckedGetter, InstanceCheckedSetter,
18817 v8::AccessorSignature::New(context->GetIsolate(), templ));
18818 context->Global()->Set(v8_str("f"), templ->GetFunction());
18820 printf("Testing positive ...\n");
18821 CompileRun("var obj = new f();");
18822 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18823 CheckInstanceCheckedAccessors(true);
18825 printf("Testing negative ...\n");
18826 CompileRun("var obj = {};"
18827 "obj.__proto__ = new f();");
18828 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18829 CheckInstanceCheckedAccessors(false);
18833 static void EmptyInterceptorGetter(
18834 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
18837 static void EmptyInterceptorSetter(
18838 Local<String> name, Local<Value> value,
18839 const v8::PropertyCallbackInfo<v8::Value>& info) {}
18842 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
18843 v8::internal::FLAG_allow_natives_syntax = true;
18844 LocalContext context;
18845 v8::HandleScope scope(context->GetIsolate());
18847 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
18848 Local<ObjectTemplate> inst = templ->InstanceTemplate();
18849 templ->InstanceTemplate()->SetNamedPropertyHandler(EmptyInterceptorGetter,
18850 EmptyInterceptorSetter);
18851 inst->SetAccessor(v8_str("foo"),
18852 InstanceCheckedGetter, InstanceCheckedSetter,
18856 v8::AccessorSignature::New(context->GetIsolate(), templ));
18857 context->Global()->Set(v8_str("f"), templ->GetFunction());
18859 printf("Testing positive ...\n");
18860 CompileRun("var obj = new f();");
18861 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18862 CheckInstanceCheckedAccessors(true);
18864 printf("Testing negative ...\n");
18865 CompileRun("var obj = {};"
18866 "obj.__proto__ = new f();");
18867 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18868 CheckInstanceCheckedAccessors(false);
18872 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
18873 v8::internal::FLAG_allow_natives_syntax = true;
18874 LocalContext context;
18875 v8::HandleScope scope(context->GetIsolate());
18877 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
18878 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
18879 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
18880 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
18882 v8::AccessorSignature::New(context->GetIsolate(), templ));
18883 context->Global()->Set(v8_str("f"), templ->GetFunction());
18885 printf("Testing positive ...\n");
18886 CompileRun("var obj = new f();");
18887 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18888 CheckInstanceCheckedAccessors(true);
18890 printf("Testing negative ...\n");
18891 CompileRun("var obj = {};"
18892 "obj.__proto__ = new f();");
18893 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18894 CheckInstanceCheckedAccessors(false);
18896 printf("Testing positive with modified prototype chain ...\n");
18897 CompileRun("var obj = new f();"
18899 "pro.__proto__ = obj.__proto__;"
18900 "obj.__proto__ = pro;");
18901 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18902 CheckInstanceCheckedAccessors(true);
18906 TEST(TryFinallyMessage) {
18907 LocalContext context;
18908 v8::HandleScope scope(context->GetIsolate());
18910 // Test that the original error message is not lost if there is a
18911 // recursive call into Javascript is done in the finally block, e.g. to
18912 // initialize an IC. (crbug.com/129171)
18913 TryCatch try_catch(context->GetIsolate());
18914 const char* trigger_ic =
18916 " throw new Error('test'); \n"
18919 " x++; \n" // Trigger an IC initialization here.
18921 CompileRun(trigger_ic);
18922 CHECK(try_catch.HasCaught());
18923 Local<Message> message = try_catch.Message();
18924 CHECK(!message.IsEmpty());
18925 CHECK_EQ(2, message->GetLineNumber());
18929 // Test that the original exception message is indeed overwritten if
18930 // a new error is thrown in the finally block.
18931 TryCatch try_catch(context->GetIsolate());
18932 const char* throw_again =
18934 " throw new Error('test'); \n"
18938 " throw new Error('again'); \n" // This is the new uncaught error.
18940 CompileRun(throw_again);
18941 CHECK(try_catch.HasCaught());
18942 Local<Message> message = try_catch.Message();
18943 CHECK(!message.IsEmpty());
18944 CHECK_EQ(6, message->GetLineNumber());
18949 static void Helper137002(bool do_store,
18951 bool remove_accessor,
18952 bool interceptor) {
18953 LocalContext context;
18954 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
18956 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
18957 FooSetInterceptor));
18959 templ->SetAccessor(v8_str("foo"),
18960 GetterWhichReturns42,
18961 SetterWhichSetsYOnThisTo23);
18963 context->Global()->Set(v8_str("obj"), templ->NewInstance());
18965 // Turn monomorphic on slow object with native accessor, then turn
18966 // polymorphic, finally optimize to create negative lookup and fail.
18967 CompileRun(do_store ?
18968 "function f(x) { x.foo = void 0; }" :
18969 "function f(x) { return x.foo; }");
18970 CompileRun("obj.y = void 0;");
18971 if (!interceptor) {
18972 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
18974 CompileRun("obj.__proto__ = null;"
18975 "f(obj); f(obj); f(obj);");
18977 CompileRun("f({});");
18979 CompileRun("obj.y = void 0;"
18980 "%OptimizeFunctionOnNextCall(f);");
18981 if (remove_accessor) {
18982 CompileRun("delete obj.foo;");
18984 CompileRun("var result = f(obj);");
18986 CompileRun("result = obj.y;");
18988 if (remove_accessor && !interceptor) {
18989 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
18991 CHECK_EQ(do_store ? 23 : 42,
18992 context->Global()->Get(v8_str("result"))->Int32Value());
18997 THREADED_TEST(Regress137002a) {
18998 i::FLAG_allow_natives_syntax = true;
18999 i::FLAG_compilation_cache = false;
19000 v8::HandleScope scope(CcTest::isolate());
19001 for (int i = 0; i < 16; i++) {
19002 Helper137002(i & 8, i & 4, i & 2, i & 1);
19007 THREADED_TEST(Regress137002b) {
19008 i::FLAG_allow_natives_syntax = true;
19009 LocalContext context;
19010 v8::Isolate* isolate = context->GetIsolate();
19011 v8::HandleScope scope(isolate);
19012 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19013 templ->SetAccessor(v8_str("foo"),
19014 GetterWhichReturns42,
19015 SetterWhichSetsYOnThisTo23);
19016 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19018 // Turn monomorphic on slow object with native accessor, then just
19019 // delete the property and fail.
19020 CompileRun("function load(x) { return x.foo; }"
19021 "function store(x) { x.foo = void 0; }"
19022 "function keyed_load(x, key) { return x[key]; }"
19023 // Second version of function has a different source (add void 0)
19024 // so that it does not share code with the first version. This
19025 // ensures that the ICs are monomorphic.
19026 "function load2(x) { void 0; return x.foo; }"
19027 "function store2(x) { void 0; x.foo = void 0; }"
19028 "function keyed_load2(x, key) { void 0; return x[key]; }"
19031 "obj.__proto__ = null;"
19033 "subobj.y = void 0;"
19034 "subobj.__proto__ = obj;"
19035 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19037 // Make the ICs monomorphic.
19038 "load(obj); load(obj);"
19039 "load2(subobj); load2(subobj);"
19040 "store(obj); store(obj);"
19041 "store2(subobj); store2(subobj);"
19042 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
19043 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
19045 // Actually test the shiny new ICs and better not crash. This
19046 // serves as a regression test for issue 142088 as well.
19051 "keyed_load(obj, 'foo');"
19052 "keyed_load2(subobj, 'foo');"
19054 // Delete the accessor. It better not be called any more now.
19057 "subobj.y = void 0;"
19059 "var load_result = load(obj);"
19060 "var load_result2 = load2(subobj);"
19061 "var keyed_load_result = keyed_load(obj, 'foo');"
19062 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
19065 "var y_from_obj = obj.y;"
19066 "var y_from_subobj = subobj.y;");
19067 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
19068 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
19069 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
19070 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
19071 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
19072 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
19076 THREADED_TEST(Regress142088) {
19077 i::FLAG_allow_natives_syntax = true;
19078 LocalContext context;
19079 v8::Isolate* isolate = context->GetIsolate();
19080 v8::HandleScope scope(isolate);
19081 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19082 templ->SetAccessor(v8_str("foo"),
19083 GetterWhichReturns42,
19084 SetterWhichSetsYOnThisTo23);
19085 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19087 CompileRun("function load(x) { return x.foo; }"
19088 "var o = Object.create(obj);"
19089 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19090 "load(o); load(o); load(o); load(o);");
19094 THREADED_TEST(Regress137496) {
19095 i::FLAG_expose_gc = true;
19096 LocalContext context;
19097 v8::HandleScope scope(context->GetIsolate());
19099 // Compile a try-finally clause where the finally block causes a GC
19100 // while there still is a message pending for external reporting.
19101 TryCatch try_catch(context->GetIsolate());
19102 try_catch.SetVerbose(true);
19103 CompileRun("try { throw new Error(); } finally { gc(); }");
19104 CHECK(try_catch.HasCaught());
19108 THREADED_TEST(Regress157124) {
19109 LocalContext context;
19110 v8::Isolate* isolate = context->GetIsolate();
19111 v8::HandleScope scope(isolate);
19112 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19113 Local<Object> obj = templ->NewInstance();
19114 obj->GetIdentityHash();
19115 obj->DeleteHiddenValue(v8_str("Bug"));
19119 THREADED_TEST(Regress2535) {
19120 LocalContext context;
19121 v8::HandleScope scope(context->GetIsolate());
19122 Local<Value> set_value = CompileRun("new Set();");
19123 Local<Object> set_object(Local<Object>::Cast(set_value));
19124 CHECK_EQ(0, set_object->InternalFieldCount());
19125 Local<Value> map_value = CompileRun("new Map();");
19126 Local<Object> map_object(Local<Object>::Cast(map_value));
19127 CHECK_EQ(0, map_object->InternalFieldCount());
19131 THREADED_TEST(Regress2746) {
19132 LocalContext context;
19133 v8::Isolate* isolate = context->GetIsolate();
19134 v8::HandleScope scope(isolate);
19135 Local<Object> obj = Object::New(isolate);
19136 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
19137 obj->SetHiddenValue(key, v8::Undefined(isolate));
19138 Local<Value> value = obj->GetHiddenValue(key);
19139 CHECK(!value.IsEmpty());
19140 CHECK(value->IsUndefined());
19144 THREADED_TEST(Regress260106) {
19145 LocalContext context;
19146 v8::Isolate* isolate = context->GetIsolate();
19147 v8::HandleScope scope(isolate);
19148 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
19150 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
19151 Local<Function> function = templ->GetFunction();
19152 CHECK(!function.IsEmpty());
19153 CHECK(function->IsFunction());
19157 THREADED_TEST(JSONParseObject) {
19158 LocalContext context;
19159 HandleScope scope(context->GetIsolate());
19160 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
19161 Handle<Object> global = context->Global();
19162 global->Set(v8_str("obj"), obj);
19163 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
19167 THREADED_TEST(JSONParseNumber) {
19168 LocalContext context;
19169 HandleScope scope(context->GetIsolate());
19170 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
19171 Handle<Object> global = context->Global();
19172 global->Set(v8_str("obj"), obj);
19173 ExpectString("JSON.stringify(obj)", "42");
19177 #if V8_OS_POSIX && !V8_OS_NACL
19178 class ThreadInterruptTest {
19180 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
19181 ~ThreadInterruptTest() {}
19184 InterruptThread i_thread(this);
19188 CHECK_EQ(kExpectedValue, sem_value_);
19192 static const int kExpectedValue = 1;
19194 class InterruptThread : public v8::base::Thread {
19196 explicit InterruptThread(ThreadInterruptTest* test)
19197 : Thread(Options("InterruptThread")), test_(test) {}
19199 virtual void Run() {
19200 struct sigaction action;
19202 // Ensure that we'll enter waiting condition
19203 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
19205 // Setup signal handler
19206 memset(&action, 0, sizeof(action));
19207 action.sa_handler = SignalHandler;
19208 sigaction(SIGCHLD, &action, NULL);
19211 kill(getpid(), SIGCHLD);
19213 // Ensure that if wait has returned because of error
19214 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
19216 // Set value and signal semaphore
19217 test_->sem_value_ = 1;
19218 test_->sem_.Signal();
19221 static void SignalHandler(int signal) {
19225 ThreadInterruptTest* test_;
19228 v8::base::Semaphore sem_;
19229 volatile int sem_value_;
19233 THREADED_TEST(SemaphoreInterruption) {
19234 ThreadInterruptTest().RunTest();
19238 #endif // V8_OS_POSIX
19241 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19246 TEST(JSONStringifyAccessCheck) {
19247 v8::V8::Initialize();
19248 v8::Isolate* isolate = CcTest::isolate();
19249 v8::HandleScope scope(isolate);
19251 // Create an ObjectTemplate for global objects and install access
19252 // check callbacks that will block access.
19253 v8::Handle<v8::ObjectTemplate> global_template =
19254 v8::ObjectTemplate::New(isolate);
19255 global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
19257 // Create a context and set an x property on it's global object.
19258 LocalContext context0(NULL, global_template);
19259 v8::Handle<v8::Object> global0 = context0->Global();
19260 global0->Set(v8_str("x"), v8_num(42));
19261 ExpectString("JSON.stringify(this)", "{\"x\":42}");
19263 for (int i = 0; i < 2; i++) {
19265 // Install a toJSON function on the second run.
19266 v8::Handle<v8::FunctionTemplate> toJSON =
19267 v8::FunctionTemplate::New(isolate, UnreachableCallback);
19269 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
19271 // Create a context with a different security token so that the
19272 // failed access check callback will be called on each access.
19273 LocalContext context1(NULL, global_template);
19274 context1->Global()->Set(v8_str("other"), global0);
19276 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
19277 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
19278 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
19283 bool access_check_fail_thrown = false;
19284 bool catch_callback_called = false;
19287 // Failed access check callback that performs a GC on each invocation.
19288 void FailedAccessCheckThrows(Local<v8::Object> target,
19289 v8::AccessType type,
19290 Local<v8::Value> data) {
19291 access_check_fail_thrown = true;
19292 i::PrintF("Access check failed. Error thrown.\n");
19293 CcTest::isolate()->ThrowException(
19294 v8::Exception::Error(v8_str("cross context")));
19298 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19299 for (int i = 0; i < args.Length(); i++) {
19300 i::PrintF("%s\n", *String::Utf8Value(args[i]));
19302 catch_callback_called = true;
19306 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19307 args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
19308 args[1]->ToString(args.GetIsolate()));
19312 void CheckCorrectThrow(const char* script) {
19313 // Test that the script, when wrapped into a try-catch, triggers the catch
19314 // clause due to failed access check throwing an exception.
19315 // The subsequent try-catch should run without any exception.
19316 access_check_fail_thrown = false;
19317 catch_callback_called = false;
19318 i::ScopedVector<char> source(1024);
19319 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
19320 CompileRun(source.start());
19321 CHECK(access_check_fail_thrown);
19322 CHECK(catch_callback_called);
19324 access_check_fail_thrown = false;
19325 catch_callback_called = false;
19326 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
19327 CHECK(!access_check_fail_thrown);
19328 CHECK(!catch_callback_called);
19332 TEST(AccessCheckThrows) {
19333 i::FLAG_allow_natives_syntax = true;
19334 i::FLAG_turbo_try_catch = true;
19335 v8::V8::Initialize();
19336 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
19337 v8::Isolate* isolate = CcTest::isolate();
19338 v8::HandleScope scope(isolate);
19340 // Create an ObjectTemplate for global objects and install access
19341 // check callbacks that will block access.
19342 v8::Handle<v8::ObjectTemplate> global_template =
19343 v8::ObjectTemplate::New(isolate);
19344 global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
19346 // Create a context and set an x property on it's global object.
19347 LocalContext context0(NULL, global_template);
19348 v8::Handle<v8::Object> global0 = context0->Global();
19350 // Create a context with a different security token so that the
19351 // failed access check callback will be called on each access.
19352 LocalContext context1(NULL, global_template);
19353 context1->Global()->Set(v8_str("other"), global0);
19355 v8::Handle<v8::FunctionTemplate> catcher_fun =
19356 v8::FunctionTemplate::New(isolate, CatcherCallback);
19357 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
19359 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
19360 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
19361 context1->Global()->Set(v8_str("has_own_property"),
19362 has_own_property_fun->GetFunction());
19365 v8::TryCatch try_catch(isolate);
19366 access_check_fail_thrown = false;
19367 CompileRun("other.x;");
19368 CHECK(access_check_fail_thrown);
19369 CHECK(try_catch.HasCaught());
19372 CheckCorrectThrow("other.x");
19373 CheckCorrectThrow("other[1]");
19374 CheckCorrectThrow("JSON.stringify(other)");
19375 CheckCorrectThrow("has_own_property(other, 'x')");
19376 CheckCorrectThrow("%GetProperty(other, 'x')");
19377 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
19378 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
19379 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
19380 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
19381 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
19382 CheckCorrectThrow("%HasProperty(other, 'x')");
19383 CheckCorrectThrow("%HasElement(other, 1)");
19384 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
19385 CheckCorrectThrow("%GetPropertyNames(other)");
19386 // PROPERTY_ATTRIBUTES_NONE = 0
19387 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
19388 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
19389 "other, 'x', null, null, 1)");
19391 // Reset the failed access check callback so it does not influence
19392 // the other tests.
19393 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19397 class RequestInterruptTestBase {
19399 RequestInterruptTestBase()
19401 isolate_(env_->GetIsolate()),
19404 should_continue_(true) {
19407 virtual ~RequestInterruptTestBase() { }
19409 virtual void StartInterruptThread() = 0;
19411 virtual void TestBody() = 0;
19414 StartInterruptThread();
19416 v8::HandleScope handle_scope(isolate_);
19420 // Verify we arrived here because interruptor was called
19421 // not due to a bug causing us to exit the loop too early.
19422 CHECK(!should_continue());
19425 void WakeUpInterruptor() {
19429 bool should_continue() const { return should_continue_; }
19431 bool ShouldContinue() {
19433 if (--warmup_ == 0) {
19434 WakeUpInterruptor();
19438 return should_continue_;
19441 static void ShouldContinueCallback(
19442 const v8::FunctionCallbackInfo<Value>& info) {
19443 RequestInterruptTestBase* test =
19444 reinterpret_cast<RequestInterruptTestBase*>(
19445 info.Data().As<v8::External>()->Value());
19446 info.GetReturnValue().Set(test->ShouldContinue());
19450 v8::Isolate* isolate_;
19451 v8::base::Semaphore sem_;
19453 bool should_continue_;
19457 class RequestInterruptTestBaseWithSimpleInterrupt
19458 : public RequestInterruptTestBase {
19460 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
19462 virtual void StartInterruptThread() {
19467 class InterruptThread : public v8::base::Thread {
19469 explicit InterruptThread(RequestInterruptTestBase* test)
19470 : Thread(Options("RequestInterruptTest")), test_(test) {}
19472 virtual void Run() {
19473 test_->sem_.Wait();
19474 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
19477 static void OnInterrupt(v8::Isolate* isolate, void* data) {
19478 reinterpret_cast<RequestInterruptTestBase*>(data)->
19479 should_continue_ = false;
19483 RequestInterruptTestBase* test_;
19486 InterruptThread i_thread;
19490 class RequestInterruptTestWithFunctionCall
19491 : public RequestInterruptTestBaseWithSimpleInterrupt {
19493 virtual void TestBody() {
19494 Local<Function> func = Function::New(
19495 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
19496 env_->Global()->Set(v8_str("ShouldContinue"), func);
19498 CompileRun("while (ShouldContinue()) { }");
19503 class RequestInterruptTestWithMethodCall
19504 : public RequestInterruptTestBaseWithSimpleInterrupt {
19506 virtual void TestBody() {
19507 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19508 v8::Local<v8::Template> proto = t->PrototypeTemplate();
19509 proto->Set(v8_str("shouldContinue"), Function::New(
19510 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
19511 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19513 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
19518 class RequestInterruptTestWithAccessor
19519 : public RequestInterruptTestBaseWithSimpleInterrupt {
19521 virtual void TestBody() {
19522 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19523 v8::Local<v8::Template> proto = t->PrototypeTemplate();
19524 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
19525 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
19526 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19528 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
19533 class RequestInterruptTestWithNativeAccessor
19534 : public RequestInterruptTestBaseWithSimpleInterrupt {
19536 virtual void TestBody() {
19537 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19538 t->InstanceTemplate()->SetNativeDataProperty(
19539 v8_str("shouldContinue"),
19540 &ShouldContinueNativeGetter,
19542 v8::External::New(isolate_, this));
19543 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19545 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
19549 static void ShouldContinueNativeGetter(
19550 Local<String> property,
19551 const v8::PropertyCallbackInfo<v8::Value>& info) {
19552 RequestInterruptTestBase* test =
19553 reinterpret_cast<RequestInterruptTestBase*>(
19554 info.Data().As<v8::External>()->Value());
19555 info.GetReturnValue().Set(test->ShouldContinue());
19560 class RequestInterruptTestWithMethodCallAndInterceptor
19561 : public RequestInterruptTestBaseWithSimpleInterrupt {
19563 virtual void TestBody() {
19564 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19565 v8::Local<v8::Template> proto = t->PrototypeTemplate();
19566 proto->Set(v8_str("shouldContinue"), Function::New(
19567 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
19568 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
19569 instance_template->SetHandler(
19570 v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
19572 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19574 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
19578 static void EmptyInterceptor(
19579 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
19583 class RequestInterruptTestWithMathAbs
19584 : public RequestInterruptTestBaseWithSimpleInterrupt {
19586 virtual void TestBody() {
19587 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
19589 WakeUpInterruptorCallback,
19590 v8::External::New(isolate_, this)));
19592 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
19594 ShouldContinueCallback,
19595 v8::External::New(isolate_, this)));
19597 i::FLAG_allow_natives_syntax = true;
19598 CompileRun("function loopish(o) {"
19600 " while (o.abs(1) > 0) {"
19601 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
19603 " if (--pre === 0) WakeUpInterruptor(o === Math);"
19608 "var obj = {abs: function () { return i-- }, x: null};"
19611 "%OptimizeFunctionOnNextCall(loopish);"
19614 i::FLAG_allow_natives_syntax = false;
19618 static void WakeUpInterruptorCallback(
19619 const v8::FunctionCallbackInfo<Value>& info) {
19620 if (!info[0]->BooleanValue()) return;
19622 RequestInterruptTestBase* test =
19623 reinterpret_cast<RequestInterruptTestBase*>(
19624 info.Data().As<v8::External>()->Value());
19625 test->WakeUpInterruptor();
19628 static void ShouldContinueCallback(
19629 const v8::FunctionCallbackInfo<Value>& info) {
19630 RequestInterruptTestBase* test =
19631 reinterpret_cast<RequestInterruptTestBase*>(
19632 info.Data().As<v8::External>()->Value());
19633 info.GetReturnValue().Set(test->should_continue());
19638 TEST(RequestInterruptTestWithFunctionCall) {
19639 RequestInterruptTestWithFunctionCall().RunTest();
19643 TEST(RequestInterruptTestWithMethodCall) {
19644 RequestInterruptTestWithMethodCall().RunTest();
19648 TEST(RequestInterruptTestWithAccessor) {
19649 RequestInterruptTestWithAccessor().RunTest();
19653 TEST(RequestInterruptTestWithNativeAccessor) {
19654 RequestInterruptTestWithNativeAccessor().RunTest();
19658 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
19659 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
19663 TEST(RequestInterruptTestWithMathAbs) {
19664 RequestInterruptTestWithMathAbs().RunTest();
19668 class RequestMultipleInterrupts : public RequestInterruptTestBase {
19670 RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
19672 virtual void StartInterruptThread() {
19676 virtual void TestBody() {
19677 Local<Function> func = Function::New(
19678 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
19679 env_->Global()->Set(v8_str("ShouldContinue"), func);
19681 CompileRun("while (ShouldContinue()) { }");
19685 class InterruptThread : public v8::base::Thread {
19687 enum { NUM_INTERRUPTS = 10 };
19688 explicit InterruptThread(RequestMultipleInterrupts* test)
19689 : Thread(Options("RequestInterruptTest")), test_(test) {}
19691 virtual void Run() {
19692 test_->sem_.Wait();
19693 for (int i = 0; i < NUM_INTERRUPTS; i++) {
19694 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
19698 static void OnInterrupt(v8::Isolate* isolate, void* data) {
19699 RequestMultipleInterrupts* test =
19700 reinterpret_cast<RequestMultipleInterrupts*>(data);
19701 test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
19705 RequestMultipleInterrupts* test_;
19708 InterruptThread i_thread;
19713 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
19716 static bool interrupt_was_called = false;
19719 void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) {
19720 interrupt_was_called = true;
19724 TEST(RequestInterruptSmallScripts) {
19726 v8::Isolate* isolate = CcTest::isolate();
19727 v8::HandleScope scope(isolate);
19729 interrupt_was_called = false;
19730 isolate->RequestInterrupt(&SmallScriptsInterruptCallback, NULL);
19731 CompileRun("(function(x){return x;})(1);");
19732 CHECK(interrupt_was_called);
19736 static Local<Value> function_new_expected_env;
19737 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
19738 CHECK(function_new_expected_env->Equals(info.Data()));
19739 info.GetReturnValue().Set(17);
19743 THREADED_TEST(FunctionNew) {
19745 v8::Isolate* isolate = env->GetIsolate();
19746 v8::HandleScope scope(isolate);
19747 Local<Object> data = v8::Object::New(isolate);
19748 function_new_expected_env = data;
19749 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
19750 env->Global()->Set(v8_str("func"), func);
19751 Local<Value> result = CompileRun("func();");
19752 CHECK(v8::Integer::New(isolate, 17)->Equals(result));
19753 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
19754 // Verify function not cached
19755 auto serial_number = handle(i::Smi::cast(v8::Utils::OpenHandle(*func)
19757 ->get_api_func_data()
19758 ->serial_number()),
19760 auto cache = i_isolate->function_cache();
19761 CHECK(cache->Lookup(serial_number)->IsTheHole());
19762 // Verify that each Function::New creates a new function instance
19763 Local<Object> data2 = v8::Object::New(isolate);
19764 function_new_expected_env = data2;
19765 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
19766 CHECK(!func2->IsNull());
19767 CHECK(!func->Equals(func2));
19768 env->Global()->Set(v8_str("func2"), func2);
19769 Local<Value> result2 = CompileRun("func2();");
19770 CHECK(v8::Integer::New(isolate, 17)->Equals(result2));
19774 TEST(EscapeableHandleScope) {
19775 HandleScope outer_scope(CcTest::isolate());
19776 LocalContext context;
19777 const int runs = 10;
19778 Local<String> values[runs];
19779 for (int i = 0; i < runs; i++) {
19780 v8::EscapableHandleScope inner_scope(CcTest::isolate());
19781 Local<String> value;
19782 if (i != 0) value = v8_str("escape value");
19783 values[i] = inner_scope.Escape(value);
19785 for (int i = 0; i < runs; i++) {
19786 Local<String> expected;
19788 CHECK(v8_str("escape value")->Equals(values[i]));
19790 CHECK(values[i].IsEmpty());
19796 static void SetterWhichExpectsThisAndHolderToDiffer(
19797 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
19798 CHECK(info.Holder() != info.This());
19802 TEST(Regress239669) {
19803 LocalContext context;
19804 v8::Isolate* isolate = context->GetIsolate();
19805 v8::HandleScope scope(isolate);
19806 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19807 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
19808 context->Global()->Set(v8_str("P"), templ->NewInstance());
19813 "C1.prototype = P;"
19814 "for (var i = 0; i < 4; i++ ) {"
19820 class ApiCallOptimizationChecker {
19822 static Local<Object> data;
19823 static Local<Object> receiver;
19824 static Local<Object> holder;
19825 static Local<Object> callee;
19828 static void OptimizationCallback(
19829 const v8::FunctionCallbackInfo<v8::Value>& info) {
19830 CHECK(callee == info.Callee());
19831 CHECK(data == info.Data());
19832 CHECK(receiver == info.This());
19833 if (info.Length() == 1) {
19834 CHECK(v8_num(1)->Equals(info[0]));
19836 CHECK(holder == info.Holder());
19838 info.GetReturnValue().Set(v8_str("returned"));
19842 enum SignatureType {
19844 kSignatureOnReceiver,
19845 kSignatureOnPrototype
19849 SignatureType signature_types[] =
19850 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
19851 for (unsigned i = 0; i < arraysize(signature_types); i++) {
19852 SignatureType signature_type = signature_types[i];
19853 for (int j = 0; j < 2; j++) {
19854 bool global = j == 0;
19855 int key = signature_type +
19856 arraysize(signature_types) * (global ? 1 : 0);
19857 Run(signature_type, global, key);
19862 void Run(SignatureType signature_type, bool global, int key) {
19863 v8::Isolate* isolate = CcTest::isolate();
19864 v8::HandleScope scope(isolate);
19865 // Build a template for signature checks.
19866 Local<v8::ObjectTemplate> signature_template;
19867 Local<v8::Signature> signature;
19869 Local<v8::FunctionTemplate> parent_template =
19870 FunctionTemplate::New(isolate);
19871 parent_template->SetHiddenPrototype(true);
19872 Local<v8::FunctionTemplate> function_template
19873 = FunctionTemplate::New(isolate);
19874 function_template->Inherit(parent_template);
19875 switch (signature_type) {
19878 case kSignatureOnReceiver:
19879 signature = v8::Signature::New(isolate, function_template);
19881 case kSignatureOnPrototype:
19882 signature = v8::Signature::New(isolate, parent_template);
19885 signature_template = function_template->InstanceTemplate();
19887 // Global object must pass checks.
19888 Local<v8::Context> context =
19889 v8::Context::New(isolate, NULL, signature_template);
19890 v8::Context::Scope context_scope(context);
19891 // Install regular object that can pass signature checks.
19892 Local<Object> function_receiver = signature_template->NewInstance();
19893 context->Global()->Set(v8_str("function_receiver"), function_receiver);
19894 // Get the holder objects.
19895 Local<Object> inner_global =
19896 Local<Object>::Cast(context->Global()->GetPrototype());
19897 // Install functions on hidden prototype object if there is one.
19898 data = Object::New(isolate);
19899 Local<FunctionTemplate> function_template = FunctionTemplate::New(
19900 isolate, OptimizationCallback, data, signature);
19901 Local<Function> function = function_template->GetFunction();
19902 Local<Object> global_holder = inner_global;
19903 Local<Object> function_holder = function_receiver;
19904 if (signature_type == kSignatureOnPrototype) {
19905 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
19906 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
19908 global_holder->Set(v8_str("g_f"), function);
19909 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
19910 function_holder->Set(v8_str("f"), function);
19911 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
19912 // Initialize expected values.
19916 receiver = context->Global();
19917 holder = inner_global;
19919 holder = function_receiver;
19920 // If not using a signature, add something else to the prototype chain
19921 // to test the case that holder != receiver
19922 if (signature_type == kNoSignature) {
19923 receiver = Local<Object>::Cast(CompileRun(
19924 "var receiver_subclass = {};\n"
19925 "receiver_subclass.__proto__ = function_receiver;\n"
19926 "receiver_subclass"));
19928 receiver = Local<Object>::Cast(CompileRun(
19929 "var receiver_subclass = function_receiver;\n"
19930 "receiver_subclass"));
19933 // With no signature, the holder is not set.
19934 if (signature_type == kNoSignature) holder = receiver;
19935 // build wrap_function
19936 i::ScopedVector<char> wrap_function(200);
19940 "function wrap_f_%d() { var f = g_f; return f(); }\n"
19941 "function wrap_get_%d() { return this.g_acc; }\n"
19942 "function wrap_set_%d() { return this.g_acc = 1; }\n",
19947 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
19948 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
19949 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
19952 // build source string
19953 i::ScopedVector<char> source(1000);
19956 "%s\n" // wrap functions
19957 "function wrap_f() { return wrap_f_%d(); }\n"
19958 "function wrap_get() { return wrap_get_%d(); }\n"
19959 "function wrap_set() { return wrap_set_%d(); }\n"
19960 "check = function(returned) {\n"
19961 " if (returned !== 'returned') { throw returned; }\n"
19964 "check(wrap_f());\n"
19965 "check(wrap_f());\n"
19966 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
19967 "check(wrap_f());\n"
19969 "check(wrap_get());\n"
19970 "check(wrap_get());\n"
19971 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
19972 "check(wrap_get());\n"
19974 "check = function(returned) {\n"
19975 " if (returned !== 1) { throw returned; }\n"
19977 "check(wrap_set());\n"
19978 "check(wrap_set());\n"
19979 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
19980 "check(wrap_set());\n",
19981 wrap_function.start(), key, key, key, key, key, key);
19982 v8::TryCatch try_catch(isolate);
19983 CompileRun(source.start());
19984 DCHECK(!try_catch.HasCaught());
19985 CHECK_EQ(9, count);
19990 Local<Object> ApiCallOptimizationChecker::data;
19991 Local<Object> ApiCallOptimizationChecker::receiver;
19992 Local<Object> ApiCallOptimizationChecker::holder;
19993 Local<Object> ApiCallOptimizationChecker::callee;
19994 int ApiCallOptimizationChecker::count = 0;
19997 TEST(FunctionCallOptimization) {
19998 i::FLAG_allow_natives_syntax = true;
19999 ApiCallOptimizationChecker checker;
20004 TEST(FunctionCallOptimizationMultipleArgs) {
20005 i::FLAG_allow_natives_syntax = true;
20006 LocalContext context;
20007 v8::Isolate* isolate = context->GetIsolate();
20008 v8::HandleScope scope(isolate);
20009 Handle<Object> global = context->Global();
20010 Local<v8::Function> function = Function::New(isolate, Returns42);
20011 global->Set(v8_str("x"), function);
20013 "function x_wrap() {\n"
20014 " for (var i = 0; i < 5; i++) {\n"
20019 "%OptimizeFunctionOnNextCall(x_wrap);"
20024 static void ReturnsSymbolCallback(
20025 const v8::FunctionCallbackInfo<v8::Value>& info) {
20026 info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
20030 TEST(ApiCallbackCanReturnSymbols) {
20031 i::FLAG_allow_natives_syntax = true;
20032 LocalContext context;
20033 v8::Isolate* isolate = context->GetIsolate();
20034 v8::HandleScope scope(isolate);
20035 Handle<Object> global = context->Global();
20036 Local<v8::Function> function = Function::New(isolate, ReturnsSymbolCallback);
20037 global->Set(v8_str("x"), function);
20039 "function x_wrap() {\n"
20040 " for (var i = 0; i < 5; i++) {\n"
20045 "%OptimizeFunctionOnNextCall(x_wrap);"
20050 TEST(EmptyApiCallback) {
20051 LocalContext context;
20052 auto isolate = context->GetIsolate();
20053 v8::HandleScope scope(isolate);
20054 auto global = context->Global();
20055 auto function = FunctionTemplate::New(isolate)->GetFunction();
20056 global->Set(v8_str("x"), function);
20058 auto result = CompileRun("x()");
20059 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20061 result = CompileRun("x(1,2,3)");
20062 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20064 result = CompileRun("7 + x.call(3) + 11");
20065 CHECK(result->IsInt32());
20066 CHECK_EQ(21, result->Int32Value());
20068 result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
20069 CHECK(result->IsInt32());
20070 CHECK_EQ(21, result->Int32Value());
20072 result = CompileRun("var y = []; x.call(y)");
20073 CHECK(result->IsArray());
20075 result = CompileRun("x.call(y, 1, 2, 3, 4)");
20076 CHECK(result->IsArray());
20080 TEST(SimpleSignatureCheck) {
20081 LocalContext context;
20082 auto isolate = context->GetIsolate();
20083 v8::HandleScope scope(isolate);
20084 auto global = context->Global();
20085 auto sig_obj = FunctionTemplate::New(isolate);
20086 auto sig = v8::Signature::New(isolate, sig_obj);
20087 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20088 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20089 global->Set(v8_str("x"), x->GetFunction());
20090 CompileRun("var s = new sig_obj();");
20092 TryCatch try_catch(isolate);
20094 CHECK(try_catch.HasCaught());
20097 TryCatch try_catch(isolate);
20098 CompileRun("x.call(1)");
20099 CHECK(try_catch.HasCaught());
20102 TryCatch try_catch(isolate);
20103 auto result = CompileRun("s.x = x; s.x()");
20104 CHECK(!try_catch.HasCaught());
20105 CHECK_EQ(42, result->Int32Value());
20108 TryCatch try_catch(isolate);
20109 auto result = CompileRun("x.call(s)");
20110 CHECK(!try_catch.HasCaught());
20111 CHECK_EQ(42, result->Int32Value());
20116 TEST(ChainSignatureCheck) {
20117 LocalContext context;
20118 auto isolate = context->GetIsolate();
20119 v8::HandleScope scope(isolate);
20120 auto global = context->Global();
20121 auto sig_obj = FunctionTemplate::New(isolate);
20122 auto sig = v8::Signature::New(isolate, sig_obj);
20123 for (int i = 0; i < 4; ++i) {
20124 auto temp = FunctionTemplate::New(isolate);
20125 temp->Inherit(sig_obj);
20128 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20129 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20130 global->Set(v8_str("x"), x->GetFunction());
20131 CompileRun("var s = new sig_obj();");
20133 TryCatch try_catch(isolate);
20135 CHECK(try_catch.HasCaught());
20138 TryCatch try_catch(isolate);
20139 CompileRun("x.call(1)");
20140 CHECK(try_catch.HasCaught());
20143 TryCatch try_catch(isolate);
20144 auto result = CompileRun("s.x = x; s.x()");
20145 CHECK(!try_catch.HasCaught());
20146 CHECK_EQ(42, result->Int32Value());
20149 TryCatch try_catch(isolate);
20150 auto result = CompileRun("x.call(s)");
20151 CHECK(!try_catch.HasCaught());
20152 CHECK_EQ(42, result->Int32Value());
20157 TEST(PrototypeSignatureCheck) {
20158 LocalContext context;
20159 auto isolate = context->GetIsolate();
20160 v8::HandleScope scope(isolate);
20161 auto global = context->Global();
20162 auto sig_obj = FunctionTemplate::New(isolate);
20163 sig_obj->SetHiddenPrototype(true);
20164 auto sig = v8::Signature::New(isolate, sig_obj);
20165 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20166 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20167 global->Set(v8_str("x"), x->GetFunction());
20168 CompileRun("s = {}; s.__proto__ = new sig_obj();");
20170 TryCatch try_catch(isolate);
20172 CHECK(try_catch.HasCaught());
20175 TryCatch try_catch(isolate);
20176 CompileRun("x.call(1)");
20177 CHECK(try_catch.HasCaught());
20180 TryCatch try_catch(isolate);
20181 auto result = CompileRun("s.x = x; s.x()");
20182 CHECK(!try_catch.HasCaught());
20183 CHECK_EQ(42, result->Int32Value());
20186 TryCatch try_catch(isolate);
20187 auto result = CompileRun("x.call(s)");
20188 CHECK(!try_catch.HasCaught());
20189 CHECK_EQ(42, result->Int32Value());
20194 static const char* last_event_message;
20195 static int last_event_status;
20196 void StoringEventLoggerCallback(const char* message, int status) {
20197 last_event_message = message;
20198 last_event_status = status;
20202 TEST(EventLogging) {
20203 v8::Isolate* isolate = CcTest::isolate();
20204 isolate->SetEventLogger(StoringEventLoggerCallback);
20205 v8::internal::HistogramTimer histogramTimer(
20206 "V8.Test", 0, 10000, v8::internal::HistogramTimer::MILLISECOND, 50,
20207 reinterpret_cast<v8::internal::Isolate*>(isolate));
20208 histogramTimer.Start();
20209 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20210 CHECK_EQ(0, last_event_status);
20211 histogramTimer.Stop();
20212 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20213 CHECK_EQ(1, last_event_status);
20218 LocalContext context;
20219 v8::Isolate* isolate = context->GetIsolate();
20220 v8::HandleScope scope(isolate);
20221 Handle<Object> global = context->Global();
20224 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20225 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
20226 Handle<v8::Promise> p = pr->GetPromise();
20227 Handle<v8::Promise> r = rr->GetPromise();
20228 CHECK_EQ(isolate, p->GetIsolate());
20230 // IsPromise predicate.
20231 CHECK(p->IsPromise());
20232 CHECK(r->IsPromise());
20233 Handle<Value> o = v8::Object::New(isolate);
20234 CHECK(!o->IsPromise());
20236 // Resolution and rejection.
20237 pr->Resolve(v8::Integer::New(isolate, 1));
20238 CHECK(p->IsPromise());
20239 rr->Reject(v8::Integer::New(isolate, 2));
20240 CHECK(r->IsPromise());
20242 // Chaining non-pending promises.
20246 "function f1(x) { x1 = x; return x+1 };\n"
20247 "function f2(x) { x2 = x; return x+1 };\n");
20248 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20249 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20252 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20253 isolate->RunMicrotasks();
20254 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20257 isolate->RunMicrotasks();
20258 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20261 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20262 isolate->RunMicrotasks();
20263 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20266 isolate->RunMicrotasks();
20267 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20269 // Chaining pending promises.
20270 CompileRun("x1 = x2 = 0;");
20271 pr = v8::Promise::Resolver::New(isolate);
20272 rr = v8::Promise::Resolver::New(isolate);
20274 pr->GetPromise()->Chain(f1);
20275 rr->GetPromise()->Catch(f2);
20276 isolate->RunMicrotasks();
20277 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20278 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20280 pr->Resolve(v8::Integer::New(isolate, 1));
20281 rr->Reject(v8::Integer::New(isolate, 2));
20282 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20283 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20285 isolate->RunMicrotasks();
20286 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20287 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20290 CompileRun("x1 = x2 = 0;");
20291 pr = v8::Promise::Resolver::New(isolate);
20292 pr->GetPromise()->Chain(f1)->Chain(f2);
20293 pr->Resolve(v8::Integer::New(isolate, 3));
20294 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20295 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20296 isolate->RunMicrotasks();
20297 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20298 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20300 CompileRun("x1 = x2 = 0;");
20301 rr = v8::Promise::Resolver::New(isolate);
20302 rr->GetPromise()->Catch(f1)->Chain(f2);
20303 rr->Reject(v8::Integer::New(isolate, 3));
20304 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20305 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20306 isolate->RunMicrotasks();
20307 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20308 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20312 TEST(PromiseThen) {
20313 LocalContext context;
20314 v8::Isolate* isolate = context->GetIsolate();
20315 v8::HandleScope scope(isolate);
20316 Handle<Object> global = context->Global();
20319 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20320 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
20321 Handle<v8::Promise> p = pr->GetPromise();
20322 Handle<v8::Promise> q = qr->GetPromise();
20324 CHECK(p->IsPromise());
20325 CHECK(q->IsPromise());
20327 pr->Resolve(v8::Integer::New(isolate, 1));
20330 // Chaining non-pending promises.
20334 "function f1(x) { x1 = x; return x+1 };\n"
20335 "function f2(x) { x2 = x; return x+1 };\n");
20336 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20337 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20341 CHECK(global->Get(v8_str("x1"))->IsNumber());
20342 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20343 isolate->RunMicrotasks();
20344 CHECK(!global->Get(v8_str("x1"))->IsNumber());
20345 CHECK(p->Equals(global->Get(v8_str("x1"))));
20348 CompileRun("x1 = x2 = 0;");
20350 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20351 isolate->RunMicrotasks();
20352 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20355 CompileRun("x1 = x2 = 0;");
20356 pr = v8::Promise::Resolver::New(isolate);
20357 qr = v8::Promise::Resolver::New(isolate);
20360 qr->GetPromise()->Then(f1)->Then(f2);
20362 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20363 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20364 isolate->RunMicrotasks();
20365 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20366 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20368 pr->Resolve(v8::Integer::New(isolate, 3));
20370 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20371 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20372 isolate->RunMicrotasks();
20373 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20374 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20378 TEST(DisallowJavascriptExecutionScope) {
20379 LocalContext context;
20380 v8::Isolate* isolate = context->GetIsolate();
20381 v8::HandleScope scope(isolate);
20382 v8::Isolate::DisallowJavascriptExecutionScope no_js(
20383 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20388 TEST(AllowJavascriptExecutionScope) {
20389 LocalContext context;
20390 v8::Isolate* isolate = context->GetIsolate();
20391 v8::HandleScope scope(isolate);
20392 v8::Isolate::DisallowJavascriptExecutionScope no_js(
20393 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20394 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20395 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20396 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
20402 TEST(ThrowOnJavascriptExecution) {
20403 LocalContext context;
20404 v8::Isolate* isolate = context->GetIsolate();
20405 v8::HandleScope scope(isolate);
20406 v8::TryCatch try_catch(isolate);
20407 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20408 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20410 CHECK(try_catch.HasCaught());
20414 TEST(Regress354123) {
20415 LocalContext current;
20416 v8::Isolate* isolate = current->GetIsolate();
20417 v8::HandleScope scope(isolate);
20419 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
20420 templ->SetAccessCheckCallbacks(AccessCounter, NULL);
20421 current->Global()->Set(v8_str("friend"), templ->NewInstance());
20423 // Test access using __proto__ from the prototype chain.
20425 CompileRun("friend.__proto__ = {};");
20426 CHECK_EQ(2, access_count);
20427 CompileRun("friend.__proto__;");
20428 CHECK_EQ(4, access_count);
20430 // Test access using __proto__ as a hijacked function (A).
20432 CompileRun("var p = Object.prototype;"
20433 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
20434 "f.call(friend, {});");
20435 CHECK_EQ(1, access_count);
20436 CompileRun("var p = Object.prototype;"
20437 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
20438 "f.call(friend);");
20439 CHECK_EQ(2, access_count);
20441 // Test access using __proto__ as a hijacked function (B).
20443 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
20444 "f.call(friend, {});");
20445 CHECK_EQ(1, access_count);
20446 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
20447 "f.call(friend);");
20448 CHECK_EQ(2, access_count);
20450 // Test access using Object.setPrototypeOf reflective method.
20452 CompileRun("Object.setPrototypeOf(friend, {});");
20453 CHECK_EQ(1, access_count);
20454 CompileRun("Object.getPrototypeOf(friend);");
20455 CHECK_EQ(2, access_count);
20459 TEST(CaptureStackTraceForStackOverflow) {
20460 v8::internal::FLAG_stack_size = 150;
20461 LocalContext current;
20462 v8::Isolate* isolate = current->GetIsolate();
20463 v8::HandleScope scope(isolate);
20464 V8::SetCaptureStackTraceForUncaughtExceptions(
20465 true, 10, v8::StackTrace::kDetailed);
20466 v8::TryCatch try_catch(isolate);
20467 CompileRun("(function f(x) { f(x+1); })(0)");
20468 CHECK(try_catch.HasCaught());
20472 TEST(ScriptNameAndLineNumber) {
20474 v8::Isolate* isolate = env->GetIsolate();
20475 v8::HandleScope scope(isolate);
20476 const char* url = "http://www.foo.com/foo.js";
20477 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
20478 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
20479 Local<Script> script = v8::ScriptCompiler::Compile(
20480 isolate, &script_source);
20481 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
20482 CHECK(!script_name.IsEmpty());
20483 CHECK(script_name->IsString());
20484 String::Utf8Value utf8_name(script_name);
20485 CHECK_EQ(0, strcmp(url, *utf8_name));
20486 int line_number = script->GetUnboundScript()->GetLineNumber(0);
20487 CHECK_EQ(13, line_number);
20490 void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
20491 const char* expected_source_mapping_url) {
20492 if (expected_source_url != NULL) {
20493 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
20494 CHECK_EQ(0, strcmp(expected_source_url, *url));
20496 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
20498 if (expected_source_mapping_url != NULL) {
20499 v8::String::Utf8Value url(
20500 script->GetUnboundScript()->GetSourceMappingURL());
20501 CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
20503 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
20507 void SourceURLHelper(const char* source, const char* expected_source_url,
20508 const char* expected_source_mapping_url) {
20509 Local<Script> script = v8_compile(source);
20510 CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
20514 TEST(ScriptSourceURLAndSourceMappingURL) {
20516 v8::Isolate* isolate = env->GetIsolate();
20517 v8::HandleScope scope(isolate);
20518 SourceURLHelper("function foo() {}\n"
20519 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
20520 SourceURLHelper("function foo() {}\n"
20521 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
20523 // Both sourceURL and sourceMappingURL.
20524 SourceURLHelper("function foo() {}\n"
20525 "//# sourceURL=bar3.js\n"
20526 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
20528 // Two source URLs; the first one is ignored.
20529 SourceURLHelper("function foo() {}\n"
20530 "//# sourceURL=ignoreme.js\n"
20531 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
20532 SourceURLHelper("function foo() {}\n"
20533 "//# sourceMappingURL=ignoreme.js\n"
20534 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
20536 // SourceURL or sourceMappingURL in the middle of the script.
20537 SourceURLHelper("function foo() {}\n"
20538 "//# sourceURL=bar7.js\n"
20539 "function baz() {}\n", "bar7.js", NULL);
20540 SourceURLHelper("function foo() {}\n"
20541 "//# sourceMappingURL=bar8.js\n"
20542 "function baz() {}\n", NULL, "bar8.js");
20544 // Too much whitespace.
20545 SourceURLHelper("function foo() {}\n"
20546 "//# sourceURL=bar9.js\n"
20547 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
20548 SourceURLHelper("function foo() {}\n"
20549 "//# sourceURL =bar11.js\n"
20550 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
20552 // Disallowed characters in value.
20553 SourceURLHelper("function foo() {}\n"
20554 "//# sourceURL=bar13 .js \n"
20555 "//# sourceMappingURL=bar14 .js \n",
20557 SourceURLHelper("function foo() {}\n"
20558 "//# sourceURL=bar15\t.js \n"
20559 "//# sourceMappingURL=bar16\t.js \n",
20561 SourceURLHelper("function foo() {}\n"
20562 "//# sourceURL=bar17'.js \n"
20563 "//# sourceMappingURL=bar18'.js \n",
20565 SourceURLHelper("function foo() {}\n"
20566 "//# sourceURL=bar19\".js \n"
20567 "//# sourceMappingURL=bar20\".js \n",
20570 // Not too much whitespace.
20571 SourceURLHelper("function foo() {}\n"
20572 "//# sourceURL= bar21.js \n"
20573 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
20577 TEST(GetOwnPropertyDescriptor) {
20579 v8::Isolate* isolate = env->GetIsolate();
20580 v8::HandleScope scope(isolate);
20582 "var x = { value : 13};"
20583 "Object.defineProperty(x, 'p0', {value : 12});"
20584 "Object.defineProperty(x, 'p1', {"
20585 " set : function(value) { this.value = value; },"
20586 " get : function() { return this.value; },"
20588 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
20589 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
20590 CHECK(desc->IsUndefined());
20591 desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
20592 CHECK(v8_num(12)->Equals(Local<Object>::Cast(desc)->Get(v8_str("value"))));
20593 desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
20594 Local<Function> set =
20595 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
20596 Local<Function> get =
20597 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
20598 CHECK(v8_num(13)->Equals(get->Call(x, 0, NULL)));
20599 Handle<Value> args[] = { v8_num(14) };
20600 set->Call(x, 1, args);
20601 CHECK(v8_num(14)->Equals(get->Call(x, 0, NULL)));
20605 TEST(Regress411877) {
20606 v8::Isolate* isolate = CcTest::isolate();
20607 v8::HandleScope handle_scope(isolate);
20608 v8::Handle<v8::ObjectTemplate> object_template =
20609 v8::ObjectTemplate::New(isolate);
20610 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
20612 v8::Handle<Context> context = Context::New(isolate);
20613 v8::Context::Scope context_scope(context);
20615 context->Global()->Set(v8_str("o"), object_template->NewInstance());
20616 CompileRun("Object.getOwnPropertyNames(o)");
20620 TEST(GetHiddenPropertyTableAfterAccessCheck) {
20621 v8::Isolate* isolate = CcTest::isolate();
20622 v8::HandleScope handle_scope(isolate);
20623 v8::Handle<v8::ObjectTemplate> object_template =
20624 v8::ObjectTemplate::New(isolate);
20625 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
20627 v8::Handle<Context> context = Context::New(isolate);
20628 v8::Context::Scope context_scope(context);
20630 v8::Handle<v8::Object> obj = object_template->NewInstance();
20631 obj->Set(v8_str("key"), v8_str("value"));
20632 obj->Delete(v8_str("key"));
20634 obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
20638 TEST(Regress411793) {
20639 v8::Isolate* isolate = CcTest::isolate();
20640 v8::HandleScope handle_scope(isolate);
20641 v8::Handle<v8::ObjectTemplate> object_template =
20642 v8::ObjectTemplate::New(isolate);
20643 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
20645 v8::Handle<Context> context = Context::New(isolate);
20646 v8::Context::Scope context_scope(context);
20648 context->Global()->Set(v8_str("o"), object_template->NewInstance());
20650 "Object.defineProperty(o, 'key', "
20651 " { get: function() {}, set: function() {} });");
20654 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
20656 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
20658 virtual size_t GetMoreData(const uint8_t** src) {
20659 // Unlike in real use cases, this function will never block.
20660 if (chunks_[index_] == NULL) {
20663 // Copy the data, since the caller takes ownership of it.
20664 size_t len = strlen(chunks_[index_]);
20665 // We don't need to zero-terminate since we return the length.
20666 uint8_t* copy = new uint8_t[len];
20667 memcpy(copy, chunks_[index_], len);
20673 // Helper for constructing a string from chunks (the compilation needs it
20675 static char* FullSourceString(const char** chunks) {
20676 size_t total_len = 0;
20677 for (size_t i = 0; chunks[i] != NULL; ++i) {
20678 total_len += strlen(chunks[i]);
20680 char* full_string = new char[total_len + 1];
20682 for (size_t i = 0; chunks[i] != NULL; ++i) {
20683 size_t len = strlen(chunks[i]);
20684 memcpy(full_string + offset, chunks[i], len);
20687 full_string[total_len] = 0;
20688 return full_string;
20692 const char** chunks_;
20697 // Helper function for running streaming tests.
20698 void RunStreamingTest(const char** chunks,
20699 v8::ScriptCompiler::StreamedSource::Encoding encoding =
20700 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
20701 bool expected_success = true,
20702 const char* expected_source_url = NULL,
20703 const char* expected_source_mapping_url = NULL) {
20705 v8::Isolate* isolate = env->GetIsolate();
20706 v8::HandleScope scope(isolate);
20707 v8::TryCatch try_catch(isolate);
20709 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
20711 v8::ScriptCompiler::ScriptStreamingTask* task =
20712 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
20714 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
20715 // task here in the main thread.
20719 // Possible errors are only produced while compiling.
20720 CHECK_EQ(false, try_catch.HasCaught());
20722 v8::ScriptOrigin origin(v8_str("http://foo.com"));
20723 char* full_source = TestSourceStream::FullSourceString(chunks);
20724 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
20725 isolate, &source, v8_str(full_source), origin);
20726 if (expected_success) {
20727 CHECK(!script.IsEmpty());
20728 v8::Handle<Value> result(script->Run());
20729 // All scripts are supposed to return the fixed value 13 when ran.
20730 CHECK_EQ(13, result->Int32Value());
20731 CheckMagicComments(script, expected_source_url,
20732 expected_source_mapping_url);
20734 CHECK(script.IsEmpty());
20735 CHECK(try_catch.HasCaught());
20737 delete[] full_source;
20741 TEST(StreamingSimpleScript) {
20742 // This script is unrealistically small, since no one chunk is enough to fill
20743 // the backing buffer of Scanner, let alone overflow it.
20744 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
20746 RunStreamingTest(chunks);
20750 TEST(StreamingBiggerScript) {
20751 const char* chunk1 =
20752 "function foo() {\n"
20753 " // Make this chunk sufficiently long so that it will overflow the\n"
20754 " // backing buffer of the Scanner.\n"
20756 " var result = 0;\n"
20757 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20759 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20761 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20763 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20764 " return result;\n"
20766 const char* chunks[] = {chunk1, "foo(); ", NULL};
20767 RunStreamingTest(chunks);
20771 TEST(StreamingScriptWithParseError) {
20772 // Test that parse errors from streamed scripts are propagated correctly.
20775 " // This will result in a parse error.\n"
20776 " var if else then foo";
20777 char chunk2[] = " 13\n";
20778 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20780 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
20783 // Test that the next script succeeds normally.
20786 " // This will be parsed successfully.\n"
20787 " function foo() { return ";
20788 char chunk2[] = " 13; }\n";
20789 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20791 RunStreamingTest(chunks);
20796 TEST(StreamingUtf8Script) {
20797 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
20799 const char* chunk1 =
20800 "function foo() {\n"
20801 " // This function will contain an UTF-8 character which is not in\n"
20803 " var foob\xec\x92\x81r = 13;\n"
20804 " return foob\xec\x92\x81r;\n"
20806 const char* chunks[] = {chunk1, "foo(); ", NULL};
20807 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20811 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
20812 // A sanity check to prove that the approach of splitting UTF-8
20813 // characters is correct. Here is an UTF-8 character which will take three
20815 const char* reference = "\xec\x92\x81";
20816 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
20819 "function foo() {\n"
20820 " // This function will contain an UTF-8 character which is not in\n"
20825 " return foob\xec\x92\x81r;\n"
20827 for (int i = 0; i < 3; ++i) {
20828 chunk2[i] = reference[i];
20830 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20831 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20835 TEST(StreamingUtf8ScriptWithSplitCharacters) {
20836 // Stream data where a multi-byte UTF-8 character is split between two data
20838 const char* reference = "\xec\x92\x81";
20840 "function foo() {\n"
20841 " // This function will contain an UTF-8 character which is not in\n"
20846 " return foob\xec\x92\x81r;\n"
20848 chunk1[strlen(chunk1) - 1] = reference[0];
20849 chunk2[0] = reference[1];
20850 chunk2[1] = reference[2];
20851 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20852 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20856 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
20857 // Tests edge cases which should still be decoded correctly.
20859 // Case 1: a chunk contains only bytes for a split character (and no other
20860 // data). This kind of a chunk would be exceptionally small, but we should
20861 // still decode it correctly.
20862 const char* reference = "\xec\x92\x81";
20863 // The small chunk is at the beginning of the split character
20866 "function foo() {\n"
20867 " // This function will contain an UTF-8 character which is not in\n"
20870 char chunk2[] = "XX";
20873 " return foob\xec\x92\x81r;\n"
20875 chunk2[0] = reference[0];
20876 chunk2[1] = reference[1];
20877 chunk3[0] = reference[2];
20878 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
20879 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20881 // The small chunk is at the end of a character
20884 "function foo() {\n"
20885 " // This function will contain an UTF-8 character which is not in\n"
20888 char chunk2[] = "XX";
20891 " return foob\xec\x92\x81r;\n"
20893 chunk1[strlen(chunk1) - 1] = reference[0];
20894 chunk2[0] = reference[1];
20895 chunk2[1] = reference[2];
20896 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
20897 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20899 // Case 2: the script ends with a multi-byte character. Make sure that it's
20900 // decoded correctly and not just ignored.
20903 "var foob\xec\x92\x81 = 13;\n"
20904 "foob\xec\x92\x81";
20905 const char* chunks[] = {chunk1, NULL};
20906 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20911 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
20912 // Test cases where a UTF-8 character is split over several chunks. Those
20913 // cases are not supported (the embedder should give the data in big enough
20914 // chunks), but we shouldn't crash, just produce a parse error.
20915 const char* reference = "\xec\x92\x81";
20917 "function foo() {\n"
20918 " // This function will contain an UTF-8 character which is not in\n"
20921 char chunk2[] = "X";
20924 " return foob\xec\x92\x81r;\n"
20926 chunk1[strlen(chunk1) - 1] = reference[0];
20927 chunk2[0] = reference[1];
20928 chunk3[0] = reference[2];
20929 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
20931 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
20935 TEST(StreamingProducesParserCache) {
20936 i::FLAG_min_preparse_length = 0;
20937 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
20941 v8::Isolate* isolate = env->GetIsolate();
20942 v8::HandleScope scope(isolate);
20944 v8::ScriptCompiler::StreamedSource source(
20945 new TestSourceStream(chunks),
20946 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
20947 v8::ScriptCompiler::ScriptStreamingTask* task =
20948 v8::ScriptCompiler::StartStreamingScript(
20949 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
20951 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
20952 // task here in the main thread.
20956 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
20957 CHECK(cached_data != NULL);
20958 CHECK(cached_data->data != NULL);
20959 CHECK(!cached_data->rejected);
20960 CHECK_GT(cached_data->length, 0);
20964 TEST(StreamingWithDebuggingDoesNotProduceParserCache) {
20965 // If the debugger is active, we should just not produce parser cache at
20966 // all. This is a regeression test: We used to produce a parser cache without
20967 // any data in it (just headers).
20968 i::FLAG_min_preparse_length = 0;
20969 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
20973 v8::Isolate* isolate = env->GetIsolate();
20974 v8::HandleScope scope(isolate);
20976 // Make the debugger active by setting a breakpoint.
20977 CompileRun("function break_here() { }");
20978 i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
20979 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("break_here"))));
20981 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
20983 debug->SetBreakPoint(func, i::Handle<i::Object>(v8::internal::Smi::FromInt(1),
20984 CcTest::i_isolate()),
20987 v8::ScriptCompiler::StreamedSource source(
20988 new TestSourceStream(chunks),
20989 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
20990 v8::ScriptCompiler::ScriptStreamingTask* task =
20991 v8::ScriptCompiler::StartStreamingScript(
20992 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
20994 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
20995 // task here in the main thread.
20999 // Check that we got no cached data.
21000 CHECK(source.GetCachedData() == NULL);
21005 TEST(StreamingScriptWithInvalidUtf8) {
21006 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
21007 // chunk don't produce a crash.
21008 const char* reference = "\xec\x92\x81\x80\x80";
21010 "function foo() {\n"
21011 " // This function will contain an UTF-8 character which is not in\n"
21013 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
21016 " return foob\xec\x92\x81\x80\x80r;\n"
21018 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
21020 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21021 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
21025 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
21026 // Regression test: Stream data where there are several multi-byte UTF-8
21027 // characters in a sequence and one of them is split between two data chunks.
21028 const char* reference = "\xec\x92\x81";
21030 "function foo() {\n"
21031 " // This function will contain an UTF-8 character which is not in\n"
21033 " var foob\xec\x92\x81X";
21036 " return foob\xec\x92\x81\xec\x92\x81r;\n"
21038 chunk1[strlen(chunk1) - 1] = reference[0];
21039 chunk2[0] = reference[1];
21040 chunk2[1] = reference[2];
21041 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21042 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21046 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
21047 // Another regression test, similar to the previous one. The difference is
21048 // that the split character is not the last one in the sequence.
21049 const char* reference = "\xec\x92\x81";
21051 "function foo() {\n"
21052 " // This function will contain an UTF-8 character which is not in\n"
21056 "XX\xec\x92\x81r = 13;\n"
21057 " return foob\xec\x92\x81\xec\x92\x81r;\n"
21059 chunk1[strlen(chunk1) - 1] = reference[0];
21060 chunk2[0] = reference[1];
21061 chunk2[1] = reference[2];
21062 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21063 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21067 TEST(StreamingWithHarmonyScopes) {
21068 // Don't use RunStreamingTest here so that both scripts get to use the same
21069 // LocalContext and HandleScope.
21071 v8::Isolate* isolate = env->GetIsolate();
21072 v8::HandleScope scope(isolate);
21074 // First, run a script with a let variable.
21075 CompileRun("\"use strict\"; let x = 1;");
21077 // Then stream a script which (erroneously) tries to introduce the same
21079 const char* chunks[] = {"\"use strict\"; let x = 2;", NULL};
21081 v8::TryCatch try_catch(isolate);
21082 v8::ScriptCompiler::StreamedSource source(
21083 new TestSourceStream(chunks),
21084 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21085 v8::ScriptCompiler::ScriptStreamingTask* task =
21086 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
21090 // Parsing should succeed (the script will be parsed and compiled in a context
21091 // independent way, so the error is not detected).
21092 CHECK_EQ(false, try_catch.HasCaught());
21094 v8::ScriptOrigin origin(v8_str("http://foo.com"));
21095 char* full_source = TestSourceStream::FullSourceString(chunks);
21096 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
21097 isolate, &source, v8_str(full_source), origin);
21098 CHECK(!script.IsEmpty());
21099 CHECK_EQ(false, try_catch.HasCaught());
21101 // Running the script exposes the error.
21102 v8::Handle<Value> result(script->Run());
21103 CHECK(result.IsEmpty());
21104 CHECK(try_catch.HasCaught());
21105 delete[] full_source;
21110 v8::Isolate::CreateParams create_params;
21111 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
21113 const char* source = "Math.sqrt(4)";
21114 const char* origin = "code cache test";
21115 v8::ScriptCompiler::CachedData* cache;
21117 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
21119 v8::Isolate::Scope iscope(isolate1);
21120 v8::HandleScope scope(isolate1);
21121 v8::Local<v8::Context> context = v8::Context::New(isolate1);
21122 v8::Context::Scope cscope(context);
21123 v8::Local<v8::String> source_string = v8_str(source);
21124 v8::ScriptOrigin script_origin(v8_str(origin));
21125 v8::ScriptCompiler::Source source(source_string, script_origin);
21126 v8::ScriptCompiler::CompileOptions option =
21127 v8::ScriptCompiler::kProduceCodeCache;
21128 v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
21129 int length = source.GetCachedData()->length;
21130 uint8_t* cache_data = new uint8_t[length];
21131 memcpy(cache_data, source.GetCachedData()->data, length);
21132 cache = new v8::ScriptCompiler::CachedData(
21133 cache_data, length, v8::ScriptCompiler::CachedData::BufferOwned);
21135 isolate1->Dispose();
21137 v8::Isolate* isolate2 = v8::Isolate::New(create_params);
21139 v8::Isolate::Scope iscope(isolate2);
21140 v8::HandleScope scope(isolate2);
21141 v8::Local<v8::Context> context = v8::Context::New(isolate2);
21142 v8::Context::Scope cscope(context);
21143 v8::Local<v8::String> source_string = v8_str(source);
21144 v8::ScriptOrigin script_origin(v8_str(origin));
21145 v8::ScriptCompiler::Source source(source_string, script_origin, cache);
21146 v8::ScriptCompiler::CompileOptions option =
21147 v8::ScriptCompiler::kConsumeCodeCache;
21148 v8::Local<v8::Script> script;
21150 i::DisallowCompilation no_compile(
21151 reinterpret_cast<i::Isolate*>(isolate2));
21152 script = v8::ScriptCompiler::Compile(context, &source, option)
21155 CHECK_EQ(2, script->Run()->ToInt32(isolate2)->Int32Value());
21157 isolate2->Dispose();
21161 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
21162 const char* garbage = "garbage garbage garbage garbage garbage garbage";
21163 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
21165 v8::ScriptCompiler::CachedData* cached_data =
21166 new v8::ScriptCompiler::CachedData(data, length);
21167 DCHECK(!cached_data->rejected);
21168 v8::ScriptOrigin origin(v8_str("origin"));
21169 v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
21170 v8::Handle<v8::Script> script =
21171 v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
21172 CHECK(cached_data->rejected);
21173 CHECK_EQ(42, script->Run()->Int32Value());
21177 TEST(InvalidCacheData) {
21178 v8::V8::Initialize();
21179 v8::HandleScope scope(CcTest::isolate());
21180 LocalContext context;
21181 TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
21182 TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
21186 TEST(ParserCacheRejectedGracefully) {
21187 i::FLAG_min_preparse_length = 0;
21188 v8::V8::Initialize();
21189 v8::HandleScope scope(CcTest::isolate());
21190 LocalContext context;
21191 // Produce valid cached data.
21192 v8::ScriptOrigin origin(v8_str("origin"));
21193 v8::Local<v8::String> source_str = v8_str("function foo() {}");
21194 v8::ScriptCompiler::Source source(source_str, origin);
21195 v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
21196 CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
21197 CHECK(!script.IsEmpty());
21198 const v8::ScriptCompiler::CachedData* original_cached_data =
21199 source.GetCachedData();
21200 CHECK(original_cached_data != NULL);
21201 CHECK(original_cached_data->data != NULL);
21202 CHECK(!original_cached_data->rejected);
21203 CHECK_GT(original_cached_data->length, 0);
21204 // Recompiling the same script with it won't reject the data.
21206 v8::ScriptCompiler::Source source_with_cached_data(
21207 source_str, origin,
21208 new v8::ScriptCompiler::CachedData(original_cached_data->data,
21209 original_cached_data->length));
21210 v8::Handle<v8::Script> script =
21211 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21212 v8::ScriptCompiler::kConsumeParserCache);
21213 CHECK(!script.IsEmpty());
21214 const v8::ScriptCompiler::CachedData* new_cached_data =
21215 source_with_cached_data.GetCachedData();
21216 CHECK(new_cached_data != NULL);
21217 CHECK(!new_cached_data->rejected);
21219 // Compile an incompatible script with the cached data. The new script doesn't
21220 // have the same starting position for the function as the old one, so the old
21221 // cached data will be incompatible with it and will be rejected.
21223 v8::Local<v8::String> incompatible_source_str =
21224 v8_str(" function foo() {}");
21225 v8::ScriptCompiler::Source source_with_cached_data(
21226 incompatible_source_str, origin,
21227 new v8::ScriptCompiler::CachedData(original_cached_data->data,
21228 original_cached_data->length));
21229 v8::Handle<v8::Script> script =
21230 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21231 v8::ScriptCompiler::kConsumeParserCache);
21232 CHECK(!script.IsEmpty());
21233 const v8::ScriptCompiler::CachedData* new_cached_data =
21234 source_with_cached_data.GetCachedData();
21235 CHECK(new_cached_data != NULL);
21236 CHECK(new_cached_data->rejected);
21241 TEST(StringConcatOverflow) {
21242 v8::V8::Initialize();
21243 v8::HandleScope scope(CcTest::isolate());
21244 RandomLengthOneByteResource* r =
21245 new RandomLengthOneByteResource(i::String::kMaxLength);
21246 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
21247 CHECK(!str.IsEmpty());
21248 v8::TryCatch try_catch(CcTest::isolate());
21249 v8::Local<v8::String> result = v8::String::Concat(str, str);
21250 CHECK(result.IsEmpty());
21251 CHECK(!try_catch.HasCaught());
21255 TEST(TurboAsmDisablesNeuter) {
21256 v8::V8::Initialize();
21257 v8::HandleScope scope(CcTest::isolate());
21258 LocalContext context;
21259 #if V8_TURBOFAN_TARGET
21260 bool should_be_neuterable = !i::FLAG_turbo_asm;
21262 bool should_be_neuterable = true;
21265 "function Module(stdlib, foreign, heap) {"
21267 " var MEM32 = new stdlib.Int32Array(heap);"
21268 " function load() { return MEM32[0]; }"
21269 " return { load: load };"
21271 "var buffer = new ArrayBuffer(4);"
21272 "Module(this, {}, buffer).load();"
21275 i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF.
21276 v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
21277 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21279 const char* store =
21280 "function Module(stdlib, foreign, heap) {"
21282 " var MEM32 = new stdlib.Int32Array(heap);"
21283 " function store() { MEM32[0] = 0; }"
21284 " return { store: store };"
21286 "var buffer = new ArrayBuffer(4);"
21287 "Module(this, {}, buffer).store();"
21290 i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF.
21291 result = CompileRun(store).As<v8::ArrayBuffer>();
21292 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21296 TEST(GetPrototypeAccessControl) {
21297 i::FLAG_allow_natives_syntax = true;
21298 v8::Isolate* isolate = CcTest::isolate();
21299 v8::HandleScope handle_scope(isolate);
21302 v8::Handle<v8::ObjectTemplate> obj_template =
21303 v8::ObjectTemplate::New(isolate);
21304 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
21306 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
21309 v8::TryCatch try_catch(isolate);
21311 "function f() { %_GetPrototype(prohibited); }"
21312 "%OptimizeFunctionOnNextCall(f);"
21314 CHECK(try_catch.HasCaught());
21319 TEST(GetPrototypeHidden) {
21320 i::FLAG_allow_natives_syntax = true;
21321 v8::Isolate* isolate = CcTest::isolate();
21322 v8::HandleScope handle_scope(isolate);
21325 Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
21326 t->SetHiddenPrototype(true);
21327 Handle<Object> proto = t->GetFunction()->NewInstance();
21328 Handle<Object> object = Object::New(isolate);
21329 Handle<Object> proto2 = Object::New(isolate);
21330 object->SetPrototype(proto);
21331 proto->SetPrototype(proto2);
21333 env->Global()->Set(v8_str("object"), object);
21334 env->Global()->Set(v8_str("proto"), proto);
21335 env->Global()->Set(v8_str("proto2"), proto2);
21337 v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
21338 CHECK(result->Equals(proto2));
21340 result = CompileRun(
21341 "function f() { return %_GetPrototype(object); }"
21342 "%OptimizeFunctionOnNextCall(f);"
21344 CHECK(result->Equals(proto2));
21348 TEST(ClassPrototypeCreationContext) {
21349 v8::Isolate* isolate = CcTest::isolate();
21350 v8::HandleScope handle_scope(isolate);
21353 Handle<Object> result = Handle<Object>::Cast(
21354 CompileRun("'use strict'; class Example { }; Example.prototype"));
21355 CHECK(env.local() == result->CreationContext());
21359 TEST(SimpleStreamingScriptWithSourceURL) {
21360 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
21361 "//# sourceURL=bar2.js\n", NULL};
21362 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21367 TEST(StreamingScriptWithSplitSourceURL) {
21368 const char* chunks[] = {"function foo() { ret", "urn 13; } f",
21369 "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
21370 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21375 TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
21376 const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
21377 " sourceMappingURL=bar2.js\n", "foo();", NULL};
21378 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
21383 TEST(NewStringRangeError) {
21384 v8::Isolate* isolate = CcTest::isolate();
21385 v8::HandleScope handle_scope(isolate);
21386 const int length = i::String::kMaxLength + 1;
21387 const int buffer_size = length * sizeof(uint16_t);
21388 void* buffer = malloc(buffer_size);
21389 if (buffer == NULL) return;
21390 memset(buffer, 'A', buffer_size);
21392 v8::TryCatch try_catch(isolate);
21393 char* data = reinterpret_cast<char*>(buffer);
21394 CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString,
21395 length).IsEmpty());
21396 CHECK(!try_catch.HasCaught());
21399 v8::TryCatch try_catch(isolate);
21400 uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
21401 CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString,
21402 length).IsEmpty());
21403 CHECK(!try_catch.HasCaught());
21406 v8::TryCatch try_catch(isolate);
21407 uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
21408 CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString,
21409 length).IsEmpty());
21410 CHECK(!try_catch.HasCaught());
21416 TEST(SealHandleScope) {
21417 v8::Isolate* isolate = CcTest::isolate();
21418 v8::HandleScope handle_scope(isolate);
21421 v8::SealHandleScope seal(isolate);
21424 v8::Local<v8::Object> obj = v8::Object::New(isolate);
21430 TEST(SealHandleScopeNested) {
21431 v8::Isolate* isolate = CcTest::isolate();
21432 v8::HandleScope handle_scope(isolate);
21435 v8::SealHandleScope seal(isolate);
21438 v8::HandleScope handle_scope(isolate);
21441 v8::Local<v8::Object> obj = v8::Object::New(isolate);
21448 static bool access_was_called = false;
21451 static bool AccessAlwaysAllowedWithFlag(Local<v8::Object> global,
21452 Local<Value> name, v8::AccessType type,
21453 Local<Value> data) {
21454 access_was_called = true;
21459 static bool AccessAlwaysBlockedWithFlag(Local<v8::Object> global,
21460 Local<Value> name, v8::AccessType type,
21461 Local<Value> data) {
21462 access_was_called = true;
21467 TEST(StrongModeAccessCheckAllowed) {
21468 i::FLAG_strong_mode = true;
21469 v8::Isolate* isolate = CcTest::isolate();
21470 v8::HandleScope handle_scope(isolate);
21471 v8::Handle<Value> value;
21472 access_was_called = false;
21474 v8::Handle<v8::ObjectTemplate> obj_template =
21475 v8::ObjectTemplate::New(isolate);
21477 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
21478 obj_template->SetAccessCheckCallbacks(AccessAlwaysAllowedWithFlag, NULL);
21480 // Create an environment
21481 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
21483 v8::Handle<v8::Object> global0 = context0->Global();
21484 global0->Set(v8_str("object"), obj_template->NewInstance());
21486 v8::TryCatch try_catch(isolate);
21487 value = CompileRun("'use strong'; object.x");
21488 CHECK(!try_catch.HasCaught());
21489 CHECK(!access_was_called);
21490 CHECK_EQ(42, value->Int32Value());
21493 v8::TryCatch try_catch(isolate);
21494 value = CompileRun("'use strong'; object.foo");
21495 CHECK(try_catch.HasCaught());
21496 CHECK(!access_was_called);
21499 v8::TryCatch try_catch(isolate);
21500 value = CompileRun("'use strong'; object[10]");
21501 CHECK(try_catch.HasCaught());
21502 CHECK(!access_was_called);
21505 // Create an environment
21506 v8::Local<Context> context1 = Context::New(isolate);
21508 v8::Handle<v8::Object> global1 = context1->Global();
21509 global1->Set(v8_str("object"), obj_template->NewInstance());
21511 v8::TryCatch try_catch(isolate);
21512 value = CompileRun("'use strong'; object.x");
21513 CHECK(!try_catch.HasCaught());
21514 CHECK(access_was_called);
21515 CHECK_EQ(42, value->Int32Value());
21517 access_was_called = false;
21519 v8::TryCatch try_catch(isolate);
21520 value = CompileRun("'use strong'; object.foo");
21521 CHECK(try_catch.HasCaught());
21522 CHECK(access_was_called);
21524 access_was_called = false;
21526 v8::TryCatch try_catch(isolate);
21527 value = CompileRun("'use strong'; object[10]");
21528 CHECK(try_catch.HasCaught());
21529 CHECK(access_was_called);
21537 TEST(StrongModeAccessCheckBlocked) {
21538 i::FLAG_strong_mode = true;
21539 v8::Isolate* isolate = CcTest::isolate();
21540 v8::HandleScope handle_scope(isolate);
21541 v8::Handle<Value> value;
21542 access_was_called = false;
21544 v8::Handle<v8::ObjectTemplate> obj_template =
21545 v8::ObjectTemplate::New(isolate);
21547 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
21548 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlockedWithFlag, NULL);
21550 // Create an environment
21551 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
21553 v8::Handle<v8::Object> global0 = context0->Global();
21554 global0->Set(v8_str("object"), obj_template->NewInstance());
21556 v8::TryCatch try_catch(isolate);
21557 value = CompileRun("'use strong'; object.x");
21558 CHECK(!try_catch.HasCaught());
21559 CHECK(!access_was_called);
21560 CHECK_EQ(42, value->Int32Value());
21563 v8::TryCatch try_catch(isolate);
21564 value = CompileRun("'use strong'; object.foo");
21565 CHECK(try_catch.HasCaught());
21566 CHECK(!access_was_called);
21569 v8::TryCatch try_catch(isolate);
21570 value = CompileRun("'use strong'; object[10]");
21571 CHECK(try_catch.HasCaught());
21572 CHECK(!access_was_called);
21575 // Create an environment
21576 v8::Local<Context> context1 = Context::New(isolate);
21578 v8::Handle<v8::Object> global1 = context1->Global();
21579 global1->Set(v8_str("object"), obj_template->NewInstance());
21581 v8::TryCatch try_catch(isolate);
21582 value = CompileRun("'use strong'; object.x");
21583 CHECK(try_catch.HasCaught());
21584 CHECK(access_was_called);
21586 access_was_called = false;
21588 v8::TryCatch try_catch(isolate);
21589 value = CompileRun("'use strong'; object.foo");
21590 CHECK(try_catch.HasCaught());
21591 CHECK(access_was_called);
21593 access_was_called = false;
21595 v8::TryCatch try_catch(isolate);
21596 value = CompileRun("'use strong'; object[10]");
21597 CHECK(try_catch.HasCaught());
21598 CHECK(access_was_called);
21606 TEST(StrongModeArityCallFromApi) {
21607 i::FLAG_strong_mode = true;
21609 v8::Isolate* isolate = env->GetIsolate();
21610 v8::HandleScope scope(isolate);
21611 Local<Function> fun;
21613 v8::TryCatch try_catch(isolate);
21614 fun = Local<Function>::Cast(CompileRun(
21615 "function f(x) { 'use strong'; }"
21618 CHECK(!try_catch.HasCaught());
21622 v8::TryCatch try_catch(isolate);
21623 fun->Call(v8::Undefined(isolate), 0, nullptr);
21624 CHECK(try_catch.HasCaught());
21628 v8::TryCatch try_catch(isolate);
21629 v8::Handle<Value> args[] = {v8_num(42)};
21630 fun->Call(v8::Undefined(isolate), arraysize(args), args);
21631 CHECK(!try_catch.HasCaught());
21635 v8::TryCatch try_catch(isolate);
21636 v8::Handle<Value> args[] = {v8_num(42), v8_num(555)};
21637 fun->Call(v8::Undefined(isolate), arraysize(args), args);
21638 CHECK(!try_catch.HasCaught());
21643 TEST(StrongModeArityCallFromApi2) {
21644 i::FLAG_strong_mode = true;
21646 v8::Isolate* isolate = env->GetIsolate();
21647 v8::HandleScope scope(isolate);
21648 Local<Function> fun;
21650 v8::TryCatch try_catch(isolate);
21651 fun = Local<Function>::Cast(CompileRun(
21656 CHECK(!try_catch.HasCaught());
21660 v8::TryCatch try_catch(isolate);
21661 fun->Call(v8::Undefined(isolate), 0, nullptr);
21662 CHECK(try_catch.HasCaught());
21666 v8::TryCatch try_catch(isolate);
21667 v8::Handle<Value> args[] = {v8_num(42)};
21668 fun->Call(v8::Undefined(isolate), arraysize(args), args);
21669 CHECK(!try_catch.HasCaught());
21673 v8::TryCatch try_catch(isolate);
21674 v8::Handle<Value> args[] = {v8_num(42), v8_num(555)};
21675 fun->Call(v8::Undefined(isolate), arraysize(args), args);
21676 CHECK(!try_catch.HasCaught());
21681 TEST(StrongObjectDelete) {
21682 i::FLAG_strong_mode = true;
21684 v8::Isolate* isolate = env->GetIsolate();
21685 v8::HandleScope scope(isolate);
21688 v8::TryCatch try_catch;
21689 obj = Local<Object>::Cast(CompileRun(
21692 CHECK(!try_catch.HasCaught());
21694 obj->ForceSet(v8_str("foo"), v8_num(1), v8::None);
21695 obj->ForceSet(v8_str("2"), v8_num(1), v8::None);
21696 CHECK(obj->HasOwnProperty(v8_str("foo")));
21697 CHECK(obj->HasOwnProperty(v8_str("2")));
21698 CHECK(!obj->Delete(v8_str("foo")));
21699 CHECK(!obj->Delete(2));
21703 static void ExtrasExportsTestRuntimeFunction(
21704 const v8::FunctionCallbackInfo<v8::Value>& args) {
21705 CHECK_EQ(3, args[0]->Int32Value());
21706 args.GetReturnValue().Set(v8_num(7));
21710 TEST(ExtrasExportsObject) {
21711 v8::Isolate* isolate = CcTest::isolate();
21712 v8::HandleScope handle_scope(isolate);
21715 // standalone.gypi ensures we include the test-extra.js file, which should
21716 // export the tested functions.
21717 v8::Local<v8::Object> exports = env->GetExtrasExportsObject();
21720 exports->Get(v8_str("testExtraShouldReturnFive")).As<v8::Function>();
21721 auto undefined = v8::Undefined(isolate);
21722 auto result = func->Call(undefined, 0, {}).As<v8::Number>();
21723 CHECK_EQ(5, result->Int32Value());
21725 v8::Handle<v8::FunctionTemplate> runtimeFunction =
21726 v8::FunctionTemplate::New(isolate, ExtrasExportsTestRuntimeFunction);
21727 exports->Set(v8_str("runtime"), runtimeFunction->GetFunction());
21729 exports->Get(v8_str("testExtraShouldCallToRuntime")).As<v8::Function>();
21730 result = func->Call(undefined, 0, {}).As<v8::Number>();
21731 CHECK_EQ(7, result->Int32Value());
21736 v8::Isolate* isolate = CcTest::isolate();
21737 v8::HandleScope handle_scope(isolate);
21740 v8::Local<v8::Map> map = v8::Map::New(isolate);
21741 CHECK(map->IsObject());
21742 CHECK(map->IsMap());
21743 CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype")));
21744 CHECK_EQ(0U, map->Size());
21746 v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
21747 CHECK(val->IsMap());
21748 map = v8::Local<v8::Map>::Cast(val);
21749 CHECK_EQ(2U, map->Size());
21751 v8::Local<v8::Array> contents = map->AsArray();
21752 CHECK_EQ(4U, contents->Length());
21753 CHECK_EQ(1, contents->Get(0).As<v8::Int32>()->Value());
21754 CHECK_EQ(2, contents->Get(1).As<v8::Int32>()->Value());
21755 CHECK_EQ(3, contents->Get(2).As<v8::Int32>()->Value());
21756 CHECK_EQ(4, contents->Get(3).As<v8::Int32>()->Value());
21758 map = v8::Map::FromArray(env.local(), contents).ToLocalChecked();
21759 CHECK_EQ(2U, map->Size());
21761 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
21762 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
21764 CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
21765 CHECK(!map->Has(env.local(), map).FromJust());
21767 CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1))
21770 CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3))
21774 CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42))
21778 CHECK(!map->Set(env.local(), map, map).IsEmpty());
21779 CHECK_EQ(3U, map->Size());
21780 CHECK(map->Has(env.local(), map).FromJust());
21782 CHECK(map->Delete(env.local(), map).FromJust());
21783 CHECK_EQ(2U, map->Size());
21784 CHECK(!map->Has(env.local(), map).FromJust());
21785 CHECK(!map->Delete(env.local(), map).FromJust());
21788 CHECK_EQ(0U, map->Size());
21792 TEST(MapFromArrayOddLength) {
21793 v8::Isolate* isolate = CcTest::isolate();
21794 v8::HandleScope handle_scope(isolate);
21796 // Odd lengths result in a null MaybeLocal.
21797 Local<v8::Array> contents = v8::Array::New(isolate, 41);
21798 CHECK(v8::Map::FromArray(env.local(), contents).IsEmpty());
21803 v8::Isolate* isolate = CcTest::isolate();
21804 v8::HandleScope handle_scope(isolate);
21807 v8::Local<v8::Set> set = v8::Set::New(isolate);
21808 CHECK(set->IsObject());
21809 CHECK(set->IsSet());
21810 CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype")));
21811 CHECK_EQ(0U, set->Size());
21813 v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
21814 CHECK(val->IsSet());
21815 set = v8::Local<v8::Set>::Cast(val);
21816 CHECK_EQ(2U, set->Size());
21818 v8::Local<v8::Array> keys = set->AsArray();
21819 CHECK_EQ(2U, keys->Length());
21820 CHECK_EQ(1, keys->Get(0).As<v8::Int32>()->Value());
21821 CHECK_EQ(2, keys->Get(1).As<v8::Int32>()->Value());
21823 set = v8::Set::FromArray(env.local(), keys).ToLocalChecked();
21824 CHECK_EQ(2U, set->Size());
21826 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
21827 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
21829 CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
21830 CHECK(!set->Has(env.local(), set).FromJust());
21832 CHECK(!set->Add(env.local(), set).IsEmpty());
21833 CHECK_EQ(3U, set->Size());
21834 CHECK(set->Has(env.local(), set).FromJust());
21836 CHECK(set->Delete(env.local(), set).FromJust());
21837 CHECK_EQ(2U, set->Size());
21838 CHECK(!set->Has(env.local(), set).FromJust());
21839 CHECK(!set->Delete(env.local(), set).FromJust());
21842 CHECK_EQ(0U, set->Size());
21846 TEST(CompatibleReceiverCheckOnCachedICHandler) {
21847 v8::Isolate* isolate = CcTest::isolate();
21848 v8::HandleScope scope(isolate);
21849 v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
21850 v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
21852 v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
21853 parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
21854 v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
21855 child->Inherit(parent);
21857 env->Global()->Set(v8_str("Child"), child->GetFunction());
21859 // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
21861 "var real = new Child();\n"
21862 "for (var i = 0; i < 3; ++i) {\n"
21866 // Check that the cached stub is never used.
21868 "var fake = Object.create(Child.prototype);\n"
21869 "var result = 0;\n"
21870 "function test(d) {\n"
21871 " if (d == 3) return;\n"
21885 static int nb_uncaught_exception_callback_calls = 0;
21888 bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
21889 ++nb_uncaught_exception_callback_calls;
21894 TEST(AbortOnUncaughtExceptionNoAbort) {
21895 v8::Isolate* isolate = CcTest::isolate();
21896 v8::HandleScope handle_scope(isolate);
21897 v8::Handle<v8::ObjectTemplate> global_template =
21898 v8::ObjectTemplate::New(isolate);
21899 LocalContext env(NULL, global_template);
21901 i::FLAG_abort_on_uncaught_exception = true;
21902 isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);
21904 CompileRun("function boom() { throw new Error(\"boom\") }");
21906 v8::Local<v8::Object> global_object = env->Global();
21907 v8::Local<v8::Function> foo =
21908 v8::Local<v8::Function>::Cast(global_object->Get(v8_str("boom")));
21910 foo->Call(global_object, 0, NULL);
21912 CHECK_EQ(1, nb_uncaught_exception_callback_calls);