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(SkipArrayBufferDuringScavenge) {
14196 v8::Isolate* isolate = env->GetIsolate();
14197 v8::HandleScope handle_scope(isolate);
14199 // Make sure the pointer looks like a heap object
14200 Local<v8::Object> tmp = v8::Object::New(isolate);
14201 uint8_t* store_ptr =
14202 reinterpret_cast<uint8_t*>(*reinterpret_cast<uintptr_t*>(*tmp));
14204 // Make `store_ptr` point to from space
14205 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
14207 // Create ArrayBuffer with pointer-that-cannot-be-visited in the backing store
14208 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, store_ptr, 8);
14210 // Should not crash,
14211 // i.e. backing store pointer should not be treated as a heap object pointer
14212 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
14213 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
14215 // Use `ab` to silence compiler warning
14216 CHECK_EQ(ab->GetContents().Data(), store_ptr);
14220 THREADED_TEST(SharedUint8Array) {
14221 i::FLAG_harmony_sharedarraybuffer = true;
14222 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array,
14223 v8::SharedArrayBuffer>(i::kExternalUint8Array, 0, 0xFF);
14227 THREADED_TEST(SharedInt8Array) {
14228 i::FLAG_harmony_sharedarraybuffer = true;
14229 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array,
14230 v8::SharedArrayBuffer>(i::kExternalInt8Array, -0x80,
14235 THREADED_TEST(SharedUint16Array) {
14236 i::FLAG_harmony_sharedarraybuffer = true;
14237 TypedArrayTestHelper<uint16_t, v8::Uint16Array, i::ExternalUint16Array,
14238 v8::SharedArrayBuffer>(i::kExternalUint16Array, 0,
14243 THREADED_TEST(SharedInt16Array) {
14244 i::FLAG_harmony_sharedarraybuffer = true;
14245 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array,
14246 v8::SharedArrayBuffer>(i::kExternalInt16Array, -0x8000,
14251 THREADED_TEST(SharedUint32Array) {
14252 i::FLAG_harmony_sharedarraybuffer = true;
14253 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array,
14254 v8::SharedArrayBuffer>(i::kExternalUint32Array, 0,
14259 THREADED_TEST(SharedInt32Array) {
14260 i::FLAG_harmony_sharedarraybuffer = true;
14261 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array,
14262 v8::SharedArrayBuffer>(i::kExternalInt32Array, INT_MIN,
14267 THREADED_TEST(SharedFloat32Array) {
14268 i::FLAG_harmony_sharedarraybuffer = true;
14269 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array,
14270 v8::SharedArrayBuffer>(i::kExternalFloat32Array, -500,
14275 THREADED_TEST(SharedFloat64Array) {
14276 i::FLAG_harmony_sharedarraybuffer = true;
14277 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array,
14278 v8::SharedArrayBuffer>(i::kExternalFloat64Array, -500,
14283 THREADED_TEST(SharedUint8ClampedArray) {
14284 i::FLAG_harmony_sharedarraybuffer = true;
14285 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray,
14286 i::ExternalUint8ClampedArray, v8::SharedArrayBuffer>(
14287 i::kExternalUint8ClampedArray, 0, 0xFF);
14291 THREADED_TEST(SharedDataView) {
14292 i::FLAG_harmony_sharedarraybuffer = true;
14293 const int kSize = 50;
14295 i::ScopedVector<uint8_t> backing_store(kSize + 2);
14298 v8::Isolate* isolate = env->GetIsolate();
14299 v8::HandleScope handle_scope(isolate);
14301 Local<v8::SharedArrayBuffer> ab =
14302 v8::SharedArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
14303 Local<v8::DataView> dv =
14304 v8::DataView::New(ab, 2, kSize);
14305 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
14306 CHECK_EQ(2u, dv->ByteOffset());
14307 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
14308 CHECK(ab->Equals(dv->Buffer()));
14312 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
14313 THREADED_TEST(Is##View) { \
14314 LocalContext env; \
14315 v8::Isolate* isolate = env->GetIsolate(); \
14316 v8::HandleScope handle_scope(isolate); \
14318 Handle<Value> result = CompileRun( \
14319 "var ab = new ArrayBuffer(128);" \
14320 "new " #View "(ab)"); \
14321 CHECK(result->IsArrayBufferView()); \
14322 CHECK(result->Is##View()); \
14323 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
14326 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
14327 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
14328 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
14329 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
14330 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
14331 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
14332 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
14333 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
14334 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
14335 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
14337 #undef IS_ARRAY_BUFFER_VIEW_TEST
14341 THREADED_TEST(ScriptContextDependence) {
14343 v8::HandleScope scope(c1->GetIsolate());
14344 const char *source = "foo";
14345 v8::Handle<v8::Script> dep = v8_compile(source);
14346 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
14347 c1->GetIsolate(), source));
14348 v8::Handle<v8::UnboundScript> indep =
14349 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
14350 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
14351 v8::Integer::New(c1->GetIsolate(), 100));
14352 CHECK_EQ(dep->Run()->Int32Value(), 100);
14353 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
14355 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
14356 v8::Integer::New(c2->GetIsolate(), 101));
14357 CHECK_EQ(dep->Run()->Int32Value(), 100);
14358 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
14362 THREADED_TEST(StackTrace) {
14363 LocalContext context;
14364 v8::HandleScope scope(context->GetIsolate());
14365 v8::TryCatch try_catch(context->GetIsolate());
14366 const char *source = "function foo() { FAIL.FAIL; }; foo();";
14367 v8::Handle<v8::String> src =
14368 v8::String::NewFromUtf8(context->GetIsolate(), source);
14369 v8::Handle<v8::String> origin =
14370 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
14371 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
14372 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
14373 ->BindToCurrentContext()
14375 CHECK(try_catch.HasCaught());
14376 v8::String::Utf8Value stack(try_catch.StackTrace());
14377 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14381 // Checks that a StackFrame has certain expected values.
14382 void checkStackFrame(const char* expected_script_name,
14383 const char* expected_func_name, int expected_line_number,
14384 int expected_column, bool is_eval, bool is_constructor,
14385 v8::Handle<v8::StackFrame> frame) {
14386 v8::HandleScope scope(CcTest::isolate());
14387 v8::String::Utf8Value func_name(frame->GetFunctionName());
14388 v8::String::Utf8Value script_name(frame->GetScriptName());
14389 if (*script_name == NULL) {
14390 // The situation where there is no associated script, like for evals.
14391 CHECK(expected_script_name == NULL);
14393 CHECK(strstr(*script_name, expected_script_name) != NULL);
14395 CHECK(strstr(*func_name, expected_func_name) != NULL);
14396 CHECK_EQ(expected_line_number, frame->GetLineNumber());
14397 CHECK_EQ(expected_column, frame->GetColumn());
14398 CHECK_EQ(is_eval, frame->IsEval());
14399 CHECK_EQ(is_constructor, frame->IsConstructor());
14403 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
14404 v8::HandleScope scope(args.GetIsolate());
14405 const char* origin = "capture-stack-trace-test";
14406 const int kOverviewTest = 1;
14407 const int kDetailedTest = 2;
14409 DCHECK(args.Length() == 1);
14411 int testGroup = args[0]->Int32Value();
14412 if (testGroup == kOverviewTest) {
14413 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
14414 args.GetIsolate(), 10, v8::StackTrace::kOverview);
14415 CHECK_EQ(4, stackTrace->GetFrameCount());
14416 checkStackFrame(origin, "bar", 2, 10, false, false,
14417 stackTrace->GetFrame(0));
14418 checkStackFrame(origin, "foo", 6, 3, false, false,
14419 stackTrace->GetFrame(1));
14420 // This is the source string inside the eval which has the call to foo.
14421 checkStackFrame(NULL, "", 1, 1, false, false, stackTrace->GetFrame(2));
14422 // The last frame is an anonymous function which has the initial eval call.
14423 checkStackFrame(origin, "", 8, 7, false, false, stackTrace->GetFrame(3));
14425 CHECK(stackTrace->AsArray()->IsArray());
14426 } else if (testGroup == kDetailedTest) {
14427 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
14428 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
14429 CHECK_EQ(4, stackTrace->GetFrameCount());
14430 checkStackFrame(origin, "bat", 4, 22, false, false,
14431 stackTrace->GetFrame(0));
14432 checkStackFrame(origin, "baz", 8, 3, false, true,
14433 stackTrace->GetFrame(1));
14434 bool is_eval = true;
14435 // This is the source string inside the eval which has the call to baz.
14436 checkStackFrame(NULL, "", 1, 1, is_eval, false, stackTrace->GetFrame(2));
14437 // The last frame is an anonymous function which has the initial eval call.
14438 checkStackFrame(origin, "", 10, 1, false, false, stackTrace->GetFrame(3));
14440 CHECK(stackTrace->AsArray()->IsArray());
14445 // Tests the C++ StackTrace API.
14446 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
14447 // THREADED_TEST(CaptureStackTrace) {
14448 TEST(CaptureStackTrace) {
14449 v8::Isolate* isolate = CcTest::isolate();
14450 v8::HandleScope scope(isolate);
14451 v8::Handle<v8::String> origin =
14452 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
14453 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
14454 templ->Set(v8_str("AnalyzeStackInNativeCode"),
14455 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
14456 LocalContext context(0, templ);
14458 // Test getting OVERVIEW information. Should ignore information that is not
14459 // script name, function name, line number, and column offset.
14460 const char *overview_source =
14461 "function bar() {\n"
14462 " var y; AnalyzeStackInNativeCode(1);\n"
14464 "function foo() {\n"
14468 "var x;eval('new foo();');";
14469 v8::Handle<v8::String> overview_src =
14470 v8::String::NewFromUtf8(isolate, overview_source);
14471 v8::ScriptCompiler::Source script_source(overview_src,
14472 v8::ScriptOrigin(origin));
14473 v8::Handle<Value> overview_result(
14474 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
14475 ->BindToCurrentContext()
14477 CHECK(!overview_result.IsEmpty());
14478 CHECK(overview_result->IsObject());
14480 // Test getting DETAILED information.
14481 const char *detailed_source =
14482 "function bat() {AnalyzeStackInNativeCode(2);\n"
14485 "function baz() {\n"
14488 "eval('new baz();');";
14489 v8::Handle<v8::String> detailed_src =
14490 v8::String::NewFromUtf8(isolate, detailed_source);
14491 // Make the script using a non-zero line and column offset.
14492 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
14493 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
14494 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
14495 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
14496 v8::Handle<v8::UnboundScript> detailed_script(
14497 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
14498 v8::Handle<Value> detailed_result(
14499 detailed_script->BindToCurrentContext()->Run());
14500 CHECK(!detailed_result.IsEmpty());
14501 CHECK(detailed_result->IsObject());
14505 static void StackTraceForUncaughtExceptionListener(
14506 v8::Handle<v8::Message> message,
14507 v8::Handle<Value>) {
14509 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14510 CHECK_EQ(2, stack_trace->GetFrameCount());
14511 checkStackFrame("origin", "foo", 2, 3, false, false,
14512 stack_trace->GetFrame(0));
14513 checkStackFrame("origin", "bar", 5, 3, false, false,
14514 stack_trace->GetFrame(1));
14518 TEST(CaptureStackTraceForUncaughtException) {
14521 v8::HandleScope scope(env->GetIsolate());
14522 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14523 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14525 CompileRunWithOrigin(
14526 "function foo() {\n"
14529 "function bar() {\n"
14533 v8::Local<v8::Object> global = env->Global();
14534 Local<Value> trouble = global->Get(v8_str("bar"));
14535 CHECK(trouble->IsFunction());
14536 Function::Cast(*trouble)->Call(global, 0, NULL);
14537 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14538 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14539 CHECK_EQ(1, report_count);
14543 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
14546 v8::HandleScope scope(env->GetIsolate());
14548 // Create an Error object first.
14549 CompileRunWithOrigin(
14550 "function foo() {\n"
14551 "e=new Error('err');\n"
14553 "function bar() {\n"
14558 v8::Local<v8::Object> global = env->Global();
14559 Local<Value> trouble = global->Get(v8_str("bar"));
14560 CHECK(trouble->IsFunction());
14561 Function::Cast(*trouble)->Call(global, 0, NULL);
14563 // Enable capturing detailed stack trace late, and throw the exception.
14564 // The detailed stack trace should be extracted from the simple stack.
14565 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
14566 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14567 CompileRunWithOrigin("throw e", "origin");
14568 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14569 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
14570 CHECK_EQ(1, report_count);
14574 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
14576 v8::HandleScope scope(env->GetIsolate());
14577 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
14579 v8::StackTrace::kDetailed);
14582 "var setters = ['column', 'lineNumber', 'scriptName',\n"
14583 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
14584 " 'isConstructor'];\n"
14585 "for (var i = 0; i < setters.length; i++) {\n"
14586 " var prop = setters[i];\n"
14587 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
14589 CompileRun("throw 'exception';");
14590 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14594 static void StackTraceFunctionNameListener(v8::Handle<v8::Message> message,
14595 v8::Handle<Value>) {
14596 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14597 CHECK_EQ(5, stack_trace->GetFrameCount());
14598 checkStackFrame("origin", "foo:0", 4, 7, false, false,
14599 stack_trace->GetFrame(0));
14600 checkStackFrame("origin", "foo:1", 5, 27, false, false,
14601 stack_trace->GetFrame(1));
14602 checkStackFrame("origin", "foo", 5, 27, false, false,
14603 stack_trace->GetFrame(2));
14604 checkStackFrame("origin", "foo", 5, 27, false, false,
14605 stack_trace->GetFrame(3));
14606 checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4));
14610 TEST(GetStackTraceContainsFunctionsWithFunctionName) {
14612 v8::HandleScope scope(env->GetIsolate());
14614 CompileRunWithOrigin(
14615 "function gen(name, counter) {\n"
14616 " var f = function foo() {\n"
14617 " if (counter === 0)\n"
14619 " gen(name, counter - 1)();\n"
14621 " if (counter == 3) {\n"
14622 " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
14624 " Object.defineProperty(f, 'name', {writable:true});\n"
14625 " if (counter == 2)\n"
14628 " f.name = name + ':' + counter;\n"
14634 v8::V8::AddMessageListener(StackTraceFunctionNameListener);
14635 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14636 CompileRunWithOrigin("gen('foo', 3)();", "origin");
14637 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14638 v8::V8::RemoveMessageListeners(StackTraceFunctionNameListener);
14642 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
14643 v8::Handle<v8::Value> data) {
14644 // Use the frame where JavaScript is called from.
14645 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14646 CHECK(!stack_trace.IsEmpty());
14647 int frame_count = stack_trace->GetFrameCount();
14648 CHECK_EQ(3, frame_count);
14649 int line_number[] = {1, 2, 5};
14650 for (int i = 0; i < frame_count; i++) {
14651 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14656 // Test that we only return the stack trace at the site where the exception
14657 // is first thrown (not where it is rethrown).
14658 TEST(RethrowStackTrace) {
14660 v8::HandleScope scope(env->GetIsolate());
14661 // We make sure that
14662 // - the stack trace of the ReferenceError in g() is reported.
14663 // - the stack trace is not overwritten when e1 is rethrown by t().
14664 // - the stack trace of e2 does not overwrite that of e1.
14665 const char* source =
14666 "function g() { error; } \n"
14667 "function f() { g(); } \n"
14668 "function t(e) { throw e; } \n"
14671 "} catch (e1) { \n"
14674 " } catch (e2) { \n"
14678 v8::V8::AddMessageListener(RethrowStackTraceHandler);
14679 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14680 CompileRun(source);
14681 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14682 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
14686 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
14687 v8::Handle<v8::Value> data) {
14688 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14689 CHECK(!stack_trace.IsEmpty());
14690 int frame_count = stack_trace->GetFrameCount();
14691 CHECK_EQ(2, frame_count);
14692 int line_number[] = {3, 7};
14693 for (int i = 0; i < frame_count; i++) {
14694 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
14699 // Test that we do not recognize identity for primitive exceptions.
14700 TEST(RethrowPrimitiveStackTrace) {
14702 v8::HandleScope scope(env->GetIsolate());
14703 // We do not capture stack trace for non Error objects on creation time.
14704 // Instead, we capture the stack trace on last throw.
14705 const char* source =
14706 "function g() { throw 404; } \n"
14707 "function f() { g(); } \n"
14708 "function t(e) { throw e; } \n"
14711 "} catch (e1) { \n"
14714 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
14715 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14716 CompileRun(source);
14717 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14718 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
14722 static void RethrowExistingStackTraceHandler(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(1, stack_trace->GetFrame(0)->GetLineNumber());
14732 // Test that the stack trace is captured when the error object is created and
14733 // not where it is thrown.
14734 TEST(RethrowExistingStackTrace) {
14736 v8::HandleScope scope(env->GetIsolate());
14737 const char* source =
14738 "var e = new Error(); \n"
14740 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
14741 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14742 CompileRun(source);
14743 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14744 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
14748 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
14749 v8::Handle<v8::Value> data) {
14750 // Use the frame where JavaScript is called from.
14751 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14752 CHECK(!stack_trace.IsEmpty());
14753 CHECK_EQ(1, stack_trace->GetFrameCount());
14754 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
14758 // Test that the stack trace is captured where the bogus Error object is thrown.
14759 TEST(RethrowBogusErrorStackTrace) {
14761 v8::HandleScope scope(env->GetIsolate());
14762 const char* source =
14763 "var e = {__proto__: new Error()} \n"
14765 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
14766 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
14767 CompileRun(source);
14768 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
14769 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
14773 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
14774 int promise_reject_counter = 0;
14775 int promise_revoke_counter = 0;
14776 int promise_reject_msg_line_number = -1;
14777 int promise_reject_msg_column_number = -1;
14778 int promise_reject_line_number = -1;
14779 int promise_reject_column_number = -1;
14780 int promise_reject_frame_count = -1;
14782 void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
14783 if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
14784 promise_reject_counter++;
14785 CcTest::global()->Set(v8_str("rejected"), reject_message.GetPromise());
14786 CcTest::global()->Set(v8_str("value"), reject_message.GetValue());
14787 v8::Handle<v8::Message> message =
14788 v8::Exception::CreateMessage(reject_message.GetValue());
14789 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
14791 promise_reject_msg_line_number = message->GetLineNumber();
14792 promise_reject_msg_column_number = message->GetStartColumn() + 1;
14794 if (!stack_trace.IsEmpty()) {
14795 promise_reject_frame_count = stack_trace->GetFrameCount();
14796 if (promise_reject_frame_count > 0) {
14797 CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
14798 promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
14799 promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn();
14801 promise_reject_line_number = -1;
14802 promise_reject_column_number = -1;
14806 promise_revoke_counter++;
14807 CcTest::global()->Set(v8_str("revoked"), reject_message.GetPromise());
14808 CHECK(reject_message.GetValue().IsEmpty());
14813 v8::Handle<v8::Promise> GetPromise(const char* name) {
14814 return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
14818 v8::Handle<v8::Value> RejectValue() {
14819 return CcTest::global()->Get(v8_str("value"));
14823 void ResetPromiseStates() {
14824 promise_reject_counter = 0;
14825 promise_revoke_counter = 0;
14826 promise_reject_msg_line_number = -1;
14827 promise_reject_msg_column_number = -1;
14828 promise_reject_line_number = -1;
14829 promise_reject_column_number = -1;
14830 promise_reject_frame_count = -1;
14831 CcTest::global()->Set(v8_str("rejected"), v8_str(""));
14832 CcTest::global()->Set(v8_str("value"), v8_str(""));
14833 CcTest::global()->Set(v8_str("revoked"), v8_str(""));
14837 TEST(PromiseRejectCallback) {
14839 v8::Isolate* isolate = env->GetIsolate();
14840 v8::HandleScope scope(isolate);
14842 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
14844 ResetPromiseStates();
14846 // Create promise p0.
14849 "var p0 = new Promise( \n"
14850 " function(res, rej) { \n"
14851 " reject = rej; \n"
14854 CHECK(!GetPromise("p0")->HasHandler());
14855 CHECK_EQ(0, promise_reject_counter);
14856 CHECK_EQ(0, promise_revoke_counter);
14858 // Add resolve handler (and default reject handler) to p0.
14859 CompileRun("var p1 = p0.then(function(){});");
14860 CHECK(GetPromise("p0")->HasHandler());
14861 CHECK(!GetPromise("p1")->HasHandler());
14862 CHECK_EQ(0, promise_reject_counter);
14863 CHECK_EQ(0, promise_revoke_counter);
14866 CompileRun("reject('ppp');");
14867 CHECK(GetPromise("p0")->HasHandler());
14868 CHECK(!GetPromise("p1")->HasHandler());
14869 CHECK_EQ(1, promise_reject_counter);
14870 CHECK_EQ(0, promise_revoke_counter);
14871 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
14872 CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
14873 CHECK(RejectValue()->Equals(v8_str("ppp")));
14875 // Reject p0 again. Callback is not triggered again.
14876 CompileRun("reject();");
14877 CHECK(GetPromise("p0")->HasHandler());
14878 CHECK(!GetPromise("p1")->HasHandler());
14879 CHECK_EQ(1, promise_reject_counter);
14880 CHECK_EQ(0, promise_revoke_counter);
14882 // Add resolve handler to p1.
14883 CompileRun("var p2 = p1.then(function(){});");
14884 CHECK(GetPromise("p0")->HasHandler());
14885 CHECK(GetPromise("p1")->HasHandler());
14886 CHECK(!GetPromise("p2")->HasHandler());
14887 CHECK_EQ(2, promise_reject_counter);
14888 CHECK_EQ(1, promise_revoke_counter);
14889 CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
14890 CHECK(RejectValue()->Equals(v8_str("ppp")));
14891 CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
14893 ResetPromiseStates();
14895 // Create promise q0.
14897 "var q0 = new Promise( \n"
14898 " function(res, rej) { \n"
14899 " reject = rej; \n"
14902 CHECK(!GetPromise("q0")->HasHandler());
14903 CHECK_EQ(0, promise_reject_counter);
14904 CHECK_EQ(0, promise_revoke_counter);
14906 // Add reject handler to q0.
14907 CompileRun("var q1 = q0.catch(function() {});");
14908 CHECK(GetPromise("q0")->HasHandler());
14909 CHECK(!GetPromise("q1")->HasHandler());
14910 CHECK_EQ(0, promise_reject_counter);
14911 CHECK_EQ(0, promise_revoke_counter);
14914 CompileRun("reject('qq')");
14915 CHECK(GetPromise("q0")->HasHandler());
14916 CHECK(!GetPromise("q1")->HasHandler());
14917 CHECK_EQ(0, promise_reject_counter);
14918 CHECK_EQ(0, promise_revoke_counter);
14920 // Add a new reject handler, which rejects by returning Promise.reject().
14921 // The returned promise q_ triggers a reject callback at first, only to
14922 // revoke it when returning it causes q2 to be rejected.
14925 "var q2 = q0.catch( \n"
14927 " q_ = Promise.reject('qqq'); \n"
14931 CHECK(GetPromise("q0")->HasHandler());
14932 CHECK(!GetPromise("q1")->HasHandler());
14933 CHECK(!GetPromise("q2")->HasHandler());
14934 CHECK(GetPromise("q_")->HasHandler());
14935 CHECK_EQ(2, promise_reject_counter);
14936 CHECK_EQ(1, promise_revoke_counter);
14937 CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
14938 CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
14939 CHECK(RejectValue()->Equals(v8_str("qqq")));
14941 // Add a reject handler to the resolved q1, which rejects by throwing.
14943 "var q3 = q1.then( \n"
14945 " throw 'qqqq'; \n"
14948 CHECK(GetPromise("q0")->HasHandler());
14949 CHECK(GetPromise("q1")->HasHandler());
14950 CHECK(!GetPromise("q2")->HasHandler());
14951 CHECK(!GetPromise("q3")->HasHandler());
14952 CHECK_EQ(3, promise_reject_counter);
14953 CHECK_EQ(1, promise_revoke_counter);
14954 CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
14955 CHECK(RejectValue()->Equals(v8_str("qqqq")));
14957 ResetPromiseStates();
14959 // Create promise r0, which has three handlers, two of which handle rejects.
14961 "var r0 = new Promise( \n"
14962 " function(res, rej) { \n"
14963 " reject = rej; \n"
14966 "var r1 = r0.catch(function() {}); \n"
14967 "var r2 = r0.then(function() {}); \n"
14968 "var r3 = r0.then(function() {}, \n"
14969 " function() {}); \n");
14970 CHECK(GetPromise("r0")->HasHandler());
14971 CHECK(!GetPromise("r1")->HasHandler());
14972 CHECK(!GetPromise("r2")->HasHandler());
14973 CHECK(!GetPromise("r3")->HasHandler());
14974 CHECK_EQ(0, promise_reject_counter);
14975 CHECK_EQ(0, promise_revoke_counter);
14978 CompileRun("reject('rrr')");
14979 CHECK(GetPromise("r0")->HasHandler());
14980 CHECK(!GetPromise("r1")->HasHandler());
14981 CHECK(!GetPromise("r2")->HasHandler());
14982 CHECK(!GetPromise("r3")->HasHandler());
14983 CHECK_EQ(1, promise_reject_counter);
14984 CHECK_EQ(0, promise_revoke_counter);
14985 CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
14986 CHECK(RejectValue()->Equals(v8_str("rrr")));
14988 // Add reject handler to r2.
14989 CompileRun("var r4 = r2.catch(function() {});");
14990 CHECK(GetPromise("r0")->HasHandler());
14991 CHECK(!GetPromise("r1")->HasHandler());
14992 CHECK(GetPromise("r2")->HasHandler());
14993 CHECK(!GetPromise("r3")->HasHandler());
14994 CHECK(!GetPromise("r4")->HasHandler());
14995 CHECK_EQ(1, promise_reject_counter);
14996 CHECK_EQ(1, promise_revoke_counter);
14997 CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
14998 CHECK(RejectValue()->Equals(v8_str("rrr")));
15000 // Add reject handlers to r4.
15001 CompileRun("var r5 = r4.then(function() {}, function() {});");
15002 CHECK(GetPromise("r0")->HasHandler());
15003 CHECK(!GetPromise("r1")->HasHandler());
15004 CHECK(GetPromise("r2")->HasHandler());
15005 CHECK(!GetPromise("r3")->HasHandler());
15006 CHECK(GetPromise("r4")->HasHandler());
15007 CHECK(!GetPromise("r5")->HasHandler());
15008 CHECK_EQ(1, promise_reject_counter);
15009 CHECK_EQ(1, promise_revoke_counter);
15011 ResetPromiseStates();
15013 // Create promise s0, which has three handlers, none of which handle rejects.
15015 "var s0 = new Promise( \n"
15016 " function(res, rej) { \n"
15017 " reject = rej; \n"
15020 "var s1 = s0.then(function() {}); \n"
15021 "var s2 = s0.then(function() {}); \n"
15022 "var s3 = s0.then(function() {}); \n");
15023 CHECK(GetPromise("s0")->HasHandler());
15024 CHECK(!GetPromise("s1")->HasHandler());
15025 CHECK(!GetPromise("s2")->HasHandler());
15026 CHECK(!GetPromise("s3")->HasHandler());
15027 CHECK_EQ(0, promise_reject_counter);
15028 CHECK_EQ(0, promise_revoke_counter);
15031 CompileRun("reject('sss')");
15032 CHECK(GetPromise("s0")->HasHandler());
15033 CHECK(!GetPromise("s1")->HasHandler());
15034 CHECK(!GetPromise("s2")->HasHandler());
15035 CHECK(!GetPromise("s3")->HasHandler());
15036 CHECK_EQ(3, promise_reject_counter);
15037 CHECK_EQ(0, promise_revoke_counter);
15038 CHECK(RejectValue()->Equals(v8_str("sss")));
15040 // Test stack frames.
15041 V8::SetCaptureStackTraceForUncaughtExceptions(true);
15043 ResetPromiseStates();
15045 // Create promise t0, which is rejected in the constructor with an error.
15046 CompileRunWithOrigin(
15047 "var t0 = new Promise( \n"
15048 " function(res, rej) { \n"
15049 " reference_error; \n"
15053 CHECK(!GetPromise("t0")->HasHandler());
15054 CHECK_EQ(1, promise_reject_counter);
15055 CHECK_EQ(0, promise_revoke_counter);
15056 CHECK_EQ(2, promise_reject_frame_count);
15057 CHECK_EQ(3, promise_reject_line_number);
15058 CHECK_EQ(5, promise_reject_column_number);
15059 CHECK_EQ(3, promise_reject_msg_line_number);
15060 CHECK_EQ(5, promise_reject_msg_column_number);
15062 ResetPromiseStates();
15064 // Create promise u0 and chain u1 to it, which is rejected via throw.
15065 CompileRunWithOrigin(
15066 "var u0 = Promise.resolve(); \n"
15067 "var u1 = u0.then( \n"
15069 " (function() { \n"
15070 " throw new Error(); \n"
15075 CHECK(GetPromise("u0")->HasHandler());
15076 CHECK(!GetPromise("u1")->HasHandler());
15077 CHECK_EQ(1, promise_reject_counter);
15078 CHECK_EQ(0, promise_revoke_counter);
15079 CHECK_EQ(2, promise_reject_frame_count);
15080 CHECK_EQ(5, promise_reject_line_number);
15081 CHECK_EQ(23, promise_reject_column_number);
15082 CHECK_EQ(5, promise_reject_msg_line_number);
15083 CHECK_EQ(23, promise_reject_msg_column_number);
15085 // Throw in u3, which handles u1's rejection.
15086 CompileRunWithOrigin(
15087 "function f() { \n"
15088 " return (function() { \n"
15089 " return new Error(); \n"
15092 "var u2 = Promise.reject(f()); \n"
15093 "var u3 = u1.catch( \n"
15099 CHECK(GetPromise("u0")->HasHandler());
15100 CHECK(GetPromise("u1")->HasHandler());
15101 CHECK(GetPromise("u2")->HasHandler());
15102 CHECK(!GetPromise("u3")->HasHandler());
15103 CHECK_EQ(3, promise_reject_counter);
15104 CHECK_EQ(2, promise_revoke_counter);
15105 CHECK_EQ(3, promise_reject_frame_count);
15106 CHECK_EQ(3, promise_reject_line_number);
15107 CHECK_EQ(12, promise_reject_column_number);
15108 CHECK_EQ(3, promise_reject_msg_line_number);
15109 CHECK_EQ(12, promise_reject_msg_column_number);
15111 ResetPromiseStates();
15113 // Create promise rejected promise v0, which is incorrectly handled by v1
15114 // via chaining cycle.
15115 CompileRunWithOrigin(
15116 "var v0 = Promise.reject(); \n"
15117 "var v1 = v0.catch( \n"
15123 CHECK(GetPromise("v0")->HasHandler());
15124 CHECK(!GetPromise("v1")->HasHandler());
15125 CHECK_EQ(2, promise_reject_counter);
15126 CHECK_EQ(1, promise_revoke_counter);
15127 CHECK_EQ(0, promise_reject_frame_count);
15128 CHECK_EQ(-1, promise_reject_line_number);
15129 CHECK_EQ(-1, promise_reject_column_number);
15131 ResetPromiseStates();
15133 // Create promise t1, which rejects by throwing syntax error from eval.
15134 CompileRunWithOrigin(
15135 "var t1 = new Promise( \n"
15136 " function(res, rej) { \n"
15137 " var content = '\\n\\\n"
15139 " eval(content); \n"
15143 CHECK(!GetPromise("t1")->HasHandler());
15144 CHECK_EQ(1, promise_reject_counter);
15145 CHECK_EQ(0, promise_revoke_counter);
15146 CHECK_EQ(2, promise_reject_frame_count);
15147 CHECK_EQ(5, promise_reject_line_number);
15148 CHECK_EQ(10, promise_reject_column_number);
15149 CHECK_EQ(2, promise_reject_msg_line_number);
15150 CHECK_EQ(7, promise_reject_msg_column_number);
15154 void AnalyzeStackOfEvalWithSourceURL(
15155 const v8::FunctionCallbackInfo<v8::Value>& args) {
15156 v8::HandleScope scope(args.GetIsolate());
15157 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15158 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15159 CHECK_EQ(5, stackTrace->GetFrameCount());
15160 v8::Handle<v8::String> url = v8_str("eval_url");
15161 for (int i = 0; i < 3; i++) {
15162 v8::Handle<v8::String> name =
15163 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15164 CHECK(!name.IsEmpty());
15165 CHECK(url->Equals(name));
15170 TEST(SourceURLInStackTrace) {
15171 v8::Isolate* isolate = CcTest::isolate();
15172 v8::HandleScope scope(isolate);
15173 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15174 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
15175 v8::FunctionTemplate::New(isolate,
15176 AnalyzeStackOfEvalWithSourceURL));
15177 LocalContext context(0, templ);
15179 const char *source =
15180 "function outer() {\n"
15181 "function bar() {\n"
15182 " AnalyzeStackOfEvalWithSourceURL();\n"
15184 "function foo() {\n"
15190 "eval('(' + outer +')()%s');";
15192 i::ScopedVector<char> code(1024);
15193 i::SNPrintF(code, source, "//# sourceURL=eval_url");
15194 CHECK(CompileRun(code.start())->IsUndefined());
15195 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
15196 CHECK(CompileRun(code.start())->IsUndefined());
15200 static int scriptIdInStack[2];
15202 void AnalyzeScriptIdInStack(
15203 const v8::FunctionCallbackInfo<v8::Value>& args) {
15204 v8::HandleScope scope(args.GetIsolate());
15205 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15206 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
15207 CHECK_EQ(2, stackTrace->GetFrameCount());
15208 for (int i = 0; i < 2; i++) {
15209 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
15214 TEST(ScriptIdInStackTrace) {
15215 v8::Isolate* isolate = CcTest::isolate();
15216 v8::HandleScope scope(isolate);
15217 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15218 templ->Set(v8_str("AnalyzeScriptIdInStack"),
15219 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
15220 LocalContext context(0, templ);
15222 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
15224 "function foo() {\n"
15225 " AnalyzeScriptIdInStack();"
15228 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
15230 for (int i = 0; i < 2; i++) {
15231 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
15232 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
15237 void AnalyzeStackOfInlineScriptWithSourceURL(
15238 const v8::FunctionCallbackInfo<v8::Value>& args) {
15239 v8::HandleScope scope(args.GetIsolate());
15240 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15241 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15242 CHECK_EQ(4, stackTrace->GetFrameCount());
15243 v8::Handle<v8::String> url = v8_str("source_url");
15244 for (int i = 0; i < 3; i++) {
15245 v8::Handle<v8::String> name =
15246 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15247 CHECK(!name.IsEmpty());
15248 CHECK(url->Equals(name));
15253 TEST(InlineScriptWithSourceURLInStackTrace) {
15254 v8::Isolate* isolate = CcTest::isolate();
15255 v8::HandleScope scope(isolate);
15256 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15257 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
15258 v8::FunctionTemplate::New(
15259 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
15260 LocalContext context(0, templ);
15262 const char *source =
15263 "function outer() {\n"
15264 "function bar() {\n"
15265 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
15267 "function foo() {\n"
15275 i::ScopedVector<char> code(1024);
15276 i::SNPrintF(code, source, "//# sourceURL=source_url");
15277 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15278 i::SNPrintF(code, source, "//@ sourceURL=source_url");
15279 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15283 void AnalyzeStackOfDynamicScriptWithSourceURL(
15284 const v8::FunctionCallbackInfo<v8::Value>& args) {
15285 v8::HandleScope scope(args.GetIsolate());
15286 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15287 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15288 CHECK_EQ(4, stackTrace->GetFrameCount());
15289 v8::Handle<v8::String> url = v8_str("source_url");
15290 for (int i = 0; i < 3; i++) {
15291 v8::Handle<v8::String> name =
15292 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15293 CHECK(!name.IsEmpty());
15294 CHECK(url->Equals(name));
15299 TEST(DynamicWithSourceURLInStackTrace) {
15300 v8::Isolate* isolate = CcTest::isolate();
15301 v8::HandleScope scope(isolate);
15302 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15303 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
15304 v8::FunctionTemplate::New(
15305 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
15306 LocalContext context(0, templ);
15308 const char *source =
15309 "function outer() {\n"
15310 "function bar() {\n"
15311 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
15313 "function foo() {\n"
15321 i::ScopedVector<char> code(1024);
15322 i::SNPrintF(code, source, "//# sourceURL=source_url");
15323 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15324 i::SNPrintF(code, source, "//@ sourceURL=source_url");
15325 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15329 TEST(DynamicWithSourceURLInStackTraceString) {
15330 LocalContext context;
15331 v8::HandleScope scope(context->GetIsolate());
15333 const char *source =
15334 "function outer() {\n"
15335 " function foo() {\n"
15342 i::ScopedVector<char> code(1024);
15343 i::SNPrintF(code, source, "//# sourceURL=source_url");
15344 v8::TryCatch try_catch(context->GetIsolate());
15345 CompileRunWithOrigin(code.start(), "", 0, 0);
15346 CHECK(try_catch.HasCaught());
15347 v8::String::Utf8Value stack(try_catch.StackTrace());
15348 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
15352 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15353 LocalContext context;
15354 v8::HandleScope scope(context->GetIsolate());
15356 const char *source =
15357 "function outer() {\n"
15358 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
15359 " //# sourceURL=source_url\";\n"
15360 " eval(scriptContents);\n"
15363 "//# sourceURL=outer_url";
15365 v8::TryCatch try_catch(context->GetIsolate());
15366 CompileRun(source);
15367 CHECK(try_catch.HasCaught());
15369 Local<v8::Message> message = try_catch.Message();
15370 Handle<Value> sourceURL =
15371 message->GetScriptOrigin().ResourceName();
15372 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15376 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15377 LocalContext context;
15378 v8::HandleScope scope(context->GetIsolate());
15380 const char *source =
15381 "function outer() {\n"
15382 " var scriptContents = \"function boo(){ boo(); }\\\n"
15383 " //# sourceURL=source_url\";\n"
15384 " eval(scriptContents);\n"
15387 "//# sourceURL=outer_url";
15389 v8::TryCatch try_catch(context->GetIsolate());
15390 CompileRun(source);
15391 CHECK(try_catch.HasCaught());
15393 Local<v8::Message> message = try_catch.Message();
15394 Handle<Value> sourceURL =
15395 message->GetScriptOrigin().ResourceName();
15396 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15400 static void CreateGarbageInOldSpace() {
15401 i::Factory* factory = CcTest::i_isolate()->factory();
15402 v8::HandleScope scope(CcTest::isolate());
15403 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
15404 for (int i = 0; i < 1000; i++) {
15405 factory->NewFixedArray(1000, i::TENURED);
15410 // Test that idle notification can be handled and eventually collects garbage.
15411 TEST(TestIdleNotification) {
15412 if (!i::FLAG_incremental_marking) return;
15413 const intptr_t MB = 1024 * 1024;
15414 const double IdlePauseInSeconds = 1.0;
15416 v8::HandleScope scope(env->GetIsolate());
15417 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
15418 CreateGarbageInOldSpace();
15419 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
15420 CHECK_GT(size_with_garbage, initial_size + MB);
15421 bool finished = false;
15422 for (int i = 0; i < 200 && !finished; i++) {
15423 if (i < 10 && CcTest::heap()->incremental_marking()->IsStopped()) {
15424 CcTest::heap()->StartIdleIncrementalMarking();
15426 finished = env->GetIsolate()->IdleNotificationDeadline(
15427 (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
15428 static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
15429 IdlePauseInSeconds);
15430 if (CcTest::heap()->mark_compact_collector()->sweeping_in_progress()) {
15431 CcTest::heap()->mark_compact_collector()->EnsureSweepingCompleted();
15434 intptr_t final_size = CcTest::heap()->SizeOfObjects();
15436 CHECK_LT(final_size, initial_size + 1);
15440 TEST(Regress2333) {
15442 for (int i = 0; i < 3; i++) {
15443 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
15447 static uint32_t* stack_limit;
15449 static void GetStackLimitCallback(
15450 const v8::FunctionCallbackInfo<v8::Value>& args) {
15451 stack_limit = reinterpret_cast<uint32_t*>(
15452 CcTest::i_isolate()->stack_guard()->real_climit());
15456 // Uses the address of a local variable to determine the stack top now.
15457 // Given a size, returns an address that is that far from the current
15459 static uint32_t* ComputeStackLimit(uint32_t size) {
15460 uint32_t* answer = &size - (size / sizeof(size));
15461 // If the size is very large and the stack is very near the bottom of
15462 // memory then the calculation above may wrap around and give an address
15463 // that is above the (downwards-growing) stack. In that case we return
15464 // a very low address.
15465 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
15470 // We need at least 165kB for an x64 debug build with clang and ASAN.
15471 static const int stack_breathing_room = 256 * i::KB;
15474 TEST(SetStackLimit) {
15475 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
15477 // Set stack limit.
15478 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
15480 // Execute a script.
15482 v8::HandleScope scope(env->GetIsolate());
15483 Local<v8::FunctionTemplate> fun_templ =
15484 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
15485 Local<Function> fun = fun_templ->GetFunction();
15486 env->Global()->Set(v8_str("get_stack_limit"), fun);
15487 CompileRun("get_stack_limit();");
15489 CHECK(stack_limit == set_limit);
15493 TEST(SetStackLimitInThread) {
15494 uint32_t* set_limit;
15496 v8::Locker locker(CcTest::isolate());
15497 set_limit = ComputeStackLimit(stack_breathing_room);
15499 // Set stack limit.
15500 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
15502 // Execute a script.
15503 v8::HandleScope scope(CcTest::isolate());
15505 Local<v8::FunctionTemplate> fun_templ =
15506 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
15507 Local<Function> fun = fun_templ->GetFunction();
15508 env->Global()->Set(v8_str("get_stack_limit"), fun);
15509 CompileRun("get_stack_limit();");
15511 CHECK(stack_limit == set_limit);
15514 v8::Locker locker(CcTest::isolate());
15515 CHECK(stack_limit == set_limit);
15520 THREADED_TEST(GetHeapStatistics) {
15522 v8::HandleScope scope(c1->GetIsolate());
15523 v8::HeapStatistics heap_statistics;
15524 CHECK_EQ(0u, heap_statistics.total_heap_size());
15525 CHECK_EQ(0u, heap_statistics.used_heap_size());
15526 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
15527 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
15528 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
15532 class VisitorImpl : public v8::ExternalResourceVisitor {
15534 explicit VisitorImpl(TestResource** resource) {
15535 for (int i = 0; i < 4; i++) {
15536 resource_[i] = resource[i];
15537 found_resource_[i] = false;
15540 virtual ~VisitorImpl() {}
15541 virtual void VisitExternalString(v8::Handle<v8::String> string) {
15542 if (!string->IsExternal()) {
15543 CHECK(string->IsExternalOneByte());
15546 v8::String::ExternalStringResource* resource =
15547 string->GetExternalStringResource();
15549 for (int i = 0; i < 4; i++) {
15550 if (resource_[i] == resource) {
15551 CHECK(!found_resource_[i]);
15552 found_resource_[i] = true;
15556 void CheckVisitedResources() {
15557 for (int i = 0; i < 4; i++) {
15558 CHECK(found_resource_[i]);
15563 v8::String::ExternalStringResource* resource_[4];
15564 bool found_resource_[4];
15568 TEST(ExternalizeOldSpaceTwoByteCons) {
15569 v8::Isolate* isolate = CcTest::isolate();
15571 v8::HandleScope scope(isolate);
15572 v8::Local<v8::String> cons =
15573 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
15574 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
15575 CcTest::heap()->CollectAllAvailableGarbage();
15576 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
15578 TestResource* resource = new TestResource(
15579 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
15580 cons->MakeExternal(resource);
15582 CHECK(cons->IsExternal());
15583 CHECK_EQ(resource, cons->GetExternalStringResource());
15584 String::Encoding encoding;
15585 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
15586 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
15590 TEST(ExternalizeOldSpaceOneByteCons) {
15591 v8::Isolate* isolate = CcTest::isolate();
15593 v8::HandleScope scope(isolate);
15594 v8::Local<v8::String> cons =
15595 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
15596 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
15597 CcTest::heap()->CollectAllAvailableGarbage();
15598 CHECK(CcTest::heap()->old_space()->Contains(*v8::Utils::OpenHandle(*cons)));
15600 TestOneByteResource* resource =
15601 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
15602 cons->MakeExternal(resource);
15604 CHECK(cons->IsExternalOneByte());
15605 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
15606 String::Encoding encoding;
15607 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
15608 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
15612 TEST(VisitExternalStrings) {
15613 v8::Isolate* isolate = CcTest::isolate();
15615 v8::HandleScope scope(isolate);
15616 const char* string = "Some string";
15617 uint16_t* two_byte_string = AsciiToTwoByteString(string);
15618 TestResource* resource[4];
15619 resource[0] = new TestResource(two_byte_string);
15620 v8::Local<v8::String> string0 =
15621 v8::String::NewExternal(env->GetIsolate(), resource[0]);
15622 resource[1] = new TestResource(two_byte_string, NULL, false);
15623 v8::Local<v8::String> string1 =
15624 v8::String::NewExternal(env->GetIsolate(), resource[1]);
15626 // Externalized symbol.
15627 resource[2] = new TestResource(two_byte_string, NULL, false);
15628 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
15629 env->GetIsolate(), string, v8::String::kInternalizedString);
15630 CHECK(string2->MakeExternal(resource[2]));
15632 // Symbolized External.
15633 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
15634 v8::Local<v8::String> string3 =
15635 v8::String::NewExternal(env->GetIsolate(), resource[3]);
15636 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
15637 // Turn into a symbol.
15638 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
15639 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
15640 string3_i).is_null());
15641 CHECK(string3_i->IsInternalizedString());
15643 // We need to add usages for string* to avoid warnings in GCC 4.7
15644 CHECK(string0->IsExternal());
15645 CHECK(string1->IsExternal());
15646 CHECK(string2->IsExternal());
15647 CHECK(string3->IsExternal());
15649 VisitorImpl visitor(resource);
15650 v8::V8::VisitExternalResources(&visitor);
15651 visitor.CheckVisitedResources();
15655 TEST(ExternalStringCollectedAtTearDown) {
15657 v8::Isolate::CreateParams create_params;
15658 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
15659 v8::Isolate* isolate = v8::Isolate::New(create_params);
15660 { v8::Isolate::Scope isolate_scope(isolate);
15661 v8::HandleScope handle_scope(isolate);
15662 const char* s = "One string to test them all, one string to find them.";
15663 TestOneByteResource* inscription =
15664 new TestOneByteResource(i::StrDup(s), &destroyed);
15665 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, 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(ExternalInternalizedStringCollectedAtTearDown) {
15679 v8::Isolate::CreateParams create_params;
15680 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
15681 v8::Isolate* isolate = v8::Isolate::New(create_params);
15682 { v8::Isolate::Scope isolate_scope(isolate);
15683 LocalContext env(isolate);
15684 v8::HandleScope handle_scope(isolate);
15685 CompileRun("var ring = 'One string to test them all';");
15686 const char* s = "One string to test them all";
15687 TestOneByteResource* inscription =
15688 new TestOneByteResource(i::StrDup(s), &destroyed);
15689 v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
15690 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
15691 ring->MakeExternal(inscription);
15692 // Ring is still alive. Orcs are roaming freely across our lands.
15693 CHECK_EQ(0, destroyed);
15697 isolate->Dispose();
15698 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
15699 CHECK_EQ(1, destroyed);
15703 TEST(ExternalInternalizedStringCollectedAtGC) {
15705 { LocalContext env;
15706 v8::HandleScope handle_scope(env->GetIsolate());
15707 CompileRun("var ring = 'One string to test them all';");
15708 const char* s = "One string to test them all";
15709 TestOneByteResource* inscription =
15710 new TestOneByteResource(i::StrDup(s), &destroyed);
15711 v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
15712 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
15713 ring->MakeExternal(inscription);
15714 // Ring is still alive. Orcs are roaming freely across our lands.
15715 CHECK_EQ(0, destroyed);
15719 // Garbage collector deals swift blows to evil.
15720 CcTest::i_isolate()->compilation_cache()->Clear();
15721 CcTest::heap()->CollectAllAvailableGarbage();
15723 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
15724 CHECK_EQ(1, destroyed);
15728 static double DoubleFromBits(uint64_t value) {
15730 i::MemCopy(&target, &value, sizeof(target));
15735 static uint64_t DoubleToBits(double value) {
15737 i::MemCopy(&target, &value, sizeof(target));
15742 static double DoubleToDateTime(double input) {
15743 double date_limit = 864e13;
15744 if (std::isnan(input) || input < -date_limit || input > date_limit) {
15745 return std::numeric_limits<double>::quiet_NaN();
15747 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
15751 // We don't have a consistent way to write 64-bit constants syntactically, so we
15752 // split them into two 32-bit constants and combine them programmatically.
15753 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
15754 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
15758 THREADED_TEST(QuietSignalingNaNs) {
15759 LocalContext context;
15760 v8::Isolate* isolate = context->GetIsolate();
15761 v8::HandleScope scope(isolate);
15762 v8::TryCatch try_catch(isolate);
15764 // Special double values.
15765 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
15766 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
15767 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
15768 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
15769 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
15770 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
15771 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
15773 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
15774 // on either side of the epoch.
15775 double date_limit = 864e13;
15777 double test_values[] = {
15799 int num_test_values = 20;
15801 for (int i = 0; i < num_test_values; i++) {
15802 double test_value = test_values[i];
15804 // Check that Number::New preserves non-NaNs and quiets SNaNs.
15805 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
15806 double stored_number = number->NumberValue();
15807 if (!std::isnan(test_value)) {
15808 CHECK_EQ(test_value, stored_number);
15810 uint64_t stored_bits = DoubleToBits(stored_number);
15811 // Check if quiet nan (bits 51..62 all set).
15812 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
15813 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
15814 // Most significant fraction bit for quiet nan is set to 0
15815 // on MIPS architecture. Allowed by IEEE-754.
15816 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15818 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
15822 // Check that Date::New preserves non-NaNs in the date range and
15824 v8::Handle<v8::Value> date =
15825 v8::Date::New(isolate, test_value);
15826 double expected_stored_date = DoubleToDateTime(test_value);
15827 double stored_date = date->NumberValue();
15828 if (!std::isnan(expected_stored_date)) {
15829 CHECK_EQ(expected_stored_date, stored_date);
15831 uint64_t stored_bits = DoubleToBits(stored_date);
15832 // Check if quiet nan (bits 51..62 all set).
15833 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
15834 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
15835 // Most significant fraction bit for quiet nan is set to 0
15836 // on MIPS architecture. Allowed by IEEE-754.
15837 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
15839 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
15846 static void SpaghettiIncident(
15847 const v8::FunctionCallbackInfo<v8::Value>& args) {
15848 v8::HandleScope scope(args.GetIsolate());
15849 v8::TryCatch tc(args.GetIsolate());
15850 v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
15852 if (tc.HasCaught())
15857 // Test that an exception can be propagated down through a spaghetti
15858 // stack using ReThrow.
15859 THREADED_TEST(SpaghettiStackReThrow) {
15860 v8::Isolate* isolate = CcTest::isolate();
15861 v8::HandleScope scope(isolate);
15862 LocalContext context;
15863 context->Global()->Set(
15864 v8::String::NewFromUtf8(isolate, "s"),
15865 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
15866 v8::TryCatch try_catch(isolate);
15870 " toString: function () {"
15880 CHECK(try_catch.HasCaught());
15881 v8::String::Utf8Value value(try_catch.Exception());
15882 CHECK_EQ(0, strcmp(*value, "Hey!"));
15887 v8::V8::Initialize();
15888 v8::Isolate* isolate = CcTest::isolate();
15889 i::FLAG_retain_maps_for_n_gc = 0;
15890 v8::HandleScope scope(isolate);
15891 v8::Local<Context> other_context;
15894 // Create a context used to keep the code from aging in the compilation
15896 other_context = Context::New(isolate);
15898 // Context-dependent context data creates reference from the compilation
15899 // cache to the global object.
15900 const char* source_simple = "1";
15902 v8::HandleScope scope(isolate);
15903 v8::Local<Context> context = Context::New(isolate);
15906 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
15907 context->SetEmbedderData(0, obj);
15908 CompileRun(source_simple);
15911 isolate->ContextDisposedNotification();
15912 for (gc_count = 1; gc_count < 10; gc_count++) {
15913 other_context->Enter();
15914 CompileRun(source_simple);
15915 other_context->Exit();
15916 CcTest::heap()->CollectAllGarbage();
15917 if (GetGlobalObjectsCount() == 1) break;
15919 CHECK_GE(2, gc_count);
15920 CHECK_EQ(1, GetGlobalObjectsCount());
15922 // Eval in a function creates reference from the compilation cache to the
15924 const char* source_eval = "function f(){eval('1')}; f()";
15926 v8::HandleScope scope(isolate);
15927 v8::Local<Context> context = Context::New(isolate);
15930 CompileRun(source_eval);
15933 isolate->ContextDisposedNotification();
15934 for (gc_count = 1; gc_count < 10; gc_count++) {
15935 other_context->Enter();
15936 CompileRun(source_eval);
15937 other_context->Exit();
15938 CcTest::heap()->CollectAllGarbage();
15939 if (GetGlobalObjectsCount() == 1) break;
15941 CHECK_GE(2, gc_count);
15942 CHECK_EQ(1, GetGlobalObjectsCount());
15944 // Looking up the line number for an exception creates reference from the
15945 // compilation cache to the global object.
15946 const char* source_exception = "function f(){throw 1;} f()";
15948 v8::HandleScope scope(isolate);
15949 v8::Local<Context> context = Context::New(isolate);
15952 v8::TryCatch try_catch(isolate);
15953 CompileRun(source_exception);
15954 CHECK(try_catch.HasCaught());
15955 v8::Handle<v8::Message> message = try_catch.Message();
15956 CHECK(!message.IsEmpty());
15957 CHECK_EQ(1, message->GetLineNumber());
15960 isolate->ContextDisposedNotification();
15961 for (gc_count = 1; gc_count < 10; gc_count++) {
15962 other_context->Enter();
15963 CompileRun(source_exception);
15964 other_context->Exit();
15965 CcTest::heap()->CollectAllGarbage();
15966 if (GetGlobalObjectsCount() == 1) break;
15968 CHECK_GE(2, gc_count);
15969 CHECK_EQ(1, GetGlobalObjectsCount());
15971 isolate->ContextDisposedNotification();
15975 THREADED_TEST(ScriptOrigin) {
15977 v8::HandleScope scope(env->GetIsolate());
15978 v8::ScriptOrigin origin = v8::ScriptOrigin(
15979 v8::String::NewFromUtf8(env->GetIsolate(), "test"),
15980 v8::Integer::New(env->GetIsolate(), 1),
15981 v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
15982 v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()),
15983 v8::String::NewFromUtf8(env->GetIsolate(), "http://sourceMapUrl"),
15984 v8::True(env->GetIsolate()));
15985 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
15986 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
15987 v8::Script::Compile(script, &origin)->Run();
15988 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
15989 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
15990 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
15991 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
15993 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
15994 CHECK_EQ(0, strcmp("test",
15995 *v8::String::Utf8Value(script_origin_f.ResourceName())));
15996 CHECK_EQ(1, script_origin_f.ResourceLineOffset()->Int32Value());
15997 CHECK(script_origin_f.Options().IsSharedCrossOrigin());
15998 CHECK(script_origin_f.Options().IsEmbedderDebugScript());
15999 CHECK(script_origin_f.Options().IsOpaque());
16000 printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
16002 CHECK_EQ(0, strcmp("http://sourceMapUrl",
16003 *v8::String::Utf8Value(script_origin_f.SourceMapUrl())));
16005 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
16006 CHECK_EQ(0, strcmp("test",
16007 *v8::String::Utf8Value(script_origin_g.ResourceName())));
16008 CHECK_EQ(1, script_origin_g.ResourceLineOffset()->Int32Value());
16009 CHECK(script_origin_g.Options().IsSharedCrossOrigin());
16010 CHECK(script_origin_g.Options().IsEmbedderDebugScript());
16011 CHECK(script_origin_g.Options().IsOpaque());
16012 CHECK_EQ(0, strcmp("http://sourceMapUrl",
16013 *v8::String::Utf8Value(script_origin_g.SourceMapUrl())));
16017 THREADED_TEST(FunctionGetInferredName) {
16019 v8::HandleScope scope(env->GetIsolate());
16020 v8::ScriptOrigin origin =
16021 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16022 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16024 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
16025 v8::Script::Compile(script, &origin)->Run();
16026 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16027 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16029 strcmp("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())));
16033 THREADED_TEST(FunctionGetDisplayName) {
16035 v8::HandleScope scope(env->GetIsolate());
16036 const char* code = "var error = false;"
16037 "function a() { this.x = 1; };"
16038 "a.displayName = 'display_a';"
16039 "var b = (function() {"
16040 " var f = function() { this.x = 2; };"
16041 " f.displayName = 'display_b';"
16044 "var c = function() {};"
16045 "c.__defineGetter__('displayName', function() {"
16047 " throw new Error();"
16050 "d.__defineGetter__('displayName', function() {"
16052 " return 'wrong_display_name';"
16055 "e.displayName = 'wrong_display_name';"
16056 "e.__defineSetter__('displayName', function() {"
16058 " throw new Error();"
16061 "f.displayName = { 'foo': 6, toString: function() {"
16063 " return 'wrong_display_name';"
16065 "var g = function() {"
16066 " arguments.callee.displayName = 'set_in_runtime';"
16069 v8::ScriptOrigin origin =
16070 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16071 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
16073 v8::Local<v8::Value> error =
16074 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
16075 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
16076 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
16077 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
16078 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
16079 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
16080 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
16081 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
16082 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
16083 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
16084 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
16085 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16086 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16087 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16088 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16089 CHECK_EQ(false, error->BooleanValue());
16090 CHECK_EQ(0, strcmp("display_a", *v8::String::Utf8Value(a->GetDisplayName())));
16091 CHECK_EQ(0, strcmp("display_b", *v8::String::Utf8Value(b->GetDisplayName())));
16092 CHECK(c->GetDisplayName()->IsUndefined());
16093 CHECK(d->GetDisplayName()->IsUndefined());
16094 CHECK(e->GetDisplayName()->IsUndefined());
16095 CHECK(f->GetDisplayName()->IsUndefined());
16097 0, strcmp("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())));
16101 THREADED_TEST(ScriptLineNumber) {
16103 v8::HandleScope scope(env->GetIsolate());
16104 v8::ScriptOrigin origin =
16105 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16106 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16107 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
16108 v8::Script::Compile(script, &origin)->Run();
16109 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16110 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16111 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16112 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16113 CHECK_EQ(0, f->GetScriptLineNumber());
16114 CHECK_EQ(2, g->GetScriptLineNumber());
16118 THREADED_TEST(ScriptColumnNumber) {
16120 v8::Isolate* isolate = env->GetIsolate();
16121 v8::HandleScope scope(isolate);
16122 v8::ScriptOrigin origin =
16123 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16124 v8::Integer::New(isolate, 3),
16125 v8::Integer::New(isolate, 2));
16126 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16127 isolate, "function foo() {}\n\n function bar() {}");
16128 v8::Script::Compile(script, &origin)->Run();
16129 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16130 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16131 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16132 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16133 CHECK_EQ(14, foo->GetScriptColumnNumber());
16134 CHECK_EQ(17, bar->GetScriptColumnNumber());
16138 THREADED_TEST(FunctionIsBuiltin) {
16140 v8::Isolate* isolate = env->GetIsolate();
16141 v8::HandleScope scope(isolate);
16142 v8::Local<v8::Function> f;
16143 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
16144 CHECK(f->IsBuiltin());
16145 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
16146 CHECK(f->IsBuiltin());
16147 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
16148 CHECK(f->IsBuiltin());
16149 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
16150 CHECK(f->IsBuiltin());
16151 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
16152 CHECK(!f->IsBuiltin());
16156 THREADED_TEST(FunctionGetScriptId) {
16158 v8::Isolate* isolate = env->GetIsolate();
16159 v8::HandleScope scope(isolate);
16160 v8::ScriptOrigin origin =
16161 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16162 v8::Integer::New(isolate, 3),
16163 v8::Integer::New(isolate, 2));
16164 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
16165 isolate, "function foo() {}\n\n function bar() {}");
16166 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
16168 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16169 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16170 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16171 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16172 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
16173 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
16177 THREADED_TEST(FunctionGetBoundFunction) {
16179 v8::HandleScope scope(env->GetIsolate());
16180 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
16181 env->GetIsolate(), "test"));
16182 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16184 "var a = new Object();\n"
16186 "function f () { return this.x };\n"
16187 "var g = f.bind(a);\n"
16189 v8::Script::Compile(script, &origin)->Run();
16190 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16191 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16192 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16193 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16194 CHECK(g->GetBoundFunction()->IsFunction());
16195 Local<v8::Function> original_function = Local<v8::Function>::Cast(
16196 g->GetBoundFunction());
16197 CHECK(f->GetName()->Equals(original_function->GetName()));
16198 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
16199 CHECK_EQ(f->GetScriptColumnNumber(),
16200 original_function->GetScriptColumnNumber());
16204 static void GetterWhichReturns42(
16205 Local<String> name,
16206 const v8::PropertyCallbackInfo<v8::Value>& info) {
16207 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16208 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16209 info.GetReturnValue().Set(v8_num(42));
16213 static void SetterWhichSetsYOnThisTo23(
16214 Local<String> name,
16215 Local<Value> value,
16216 const v8::PropertyCallbackInfo<void>& info) {
16217 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16218 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16219 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16223 void FooGetInterceptor(Local<Name> name,
16224 const v8::PropertyCallbackInfo<v8::Value>& info) {
16225 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16226 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16227 if (!name->Equals(v8_str("foo"))) return;
16228 info.GetReturnValue().Set(v8_num(42));
16232 void FooSetInterceptor(Local<Name> name, Local<Value> value,
16233 const v8::PropertyCallbackInfo<v8::Value>& info) {
16234 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16235 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16236 if (!name->Equals(v8_str("foo"))) return;
16237 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16238 info.GetReturnValue().Set(v8_num(23));
16242 TEST(SetterOnConstructorPrototype) {
16243 v8::Isolate* isolate = CcTest::isolate();
16244 v8::HandleScope scope(isolate);
16245 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16246 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16247 SetterWhichSetsYOnThisTo23);
16248 LocalContext context;
16249 context->Global()->Set(v8_str("P"), templ->NewInstance());
16250 CompileRun("function C1() {"
16253 "C1.prototype = P;"
16257 "C2.prototype = { };"
16258 "C2.prototype.__proto__ = P;");
16260 v8::Local<v8::Script> script;
16261 script = v8_compile("new C1();");
16262 for (int i = 0; i < 10; i++) {
16263 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16264 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16265 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16268 script = v8_compile("new C2();");
16269 for (int i = 0; i < 10; i++) {
16270 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16271 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
16272 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
16277 static void NamedPropertyGetterWhichReturns42(
16278 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
16279 info.GetReturnValue().Set(v8_num(42));
16283 static void NamedPropertySetterWhichSetsYOnThisTo23(
16284 Local<Name> name, Local<Value> value,
16285 const v8::PropertyCallbackInfo<v8::Value>& info) {
16286 if (name->Equals(v8_str("x"))) {
16287 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16292 THREADED_TEST(InterceptorOnConstructorPrototype) {
16293 v8::Isolate* isolate = CcTest::isolate();
16294 v8::HandleScope scope(isolate);
16295 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16296 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
16297 NamedPropertyGetterWhichReturns42,
16298 NamedPropertySetterWhichSetsYOnThisTo23));
16299 LocalContext context;
16300 context->Global()->Set(v8_str("P"), templ->NewInstance());
16301 CompileRun("function C1() {"
16304 "C1.prototype = P;"
16308 "C2.prototype = { };"
16309 "C2.prototype.__proto__ = P;");
16311 v8::Local<v8::Script> script;
16312 script = v8_compile("new C1();");
16313 for (int i = 0; i < 10; i++) {
16314 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16315 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16316 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16319 script = v8_compile("new C2();");
16320 for (int i = 0; i < 10; i++) {
16321 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16322 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
16323 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
16329 const char* source = "function C1() {"
16332 "C1.prototype = P;";
16334 LocalContext context;
16335 v8::Isolate* isolate = context->GetIsolate();
16336 v8::HandleScope scope(isolate);
16337 v8::Local<v8::Script> script;
16339 // Use a simple object as prototype.
16340 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
16341 prototype->Set(v8_str("y"), v8_num(42));
16342 context->Global()->Set(v8_str("P"), prototype);
16344 // This compile will add the code to the compilation cache.
16345 CompileRun(source);
16347 script = v8_compile("new C1();");
16348 // Allow enough iterations for the inobject slack tracking logic
16349 // to finalize instance size and install the fast construct stub.
16350 for (int i = 0; i < 256; i++) {
16351 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16352 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16353 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16356 // Use an API object with accessors as prototype.
16357 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16358 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16359 SetterWhichSetsYOnThisTo23);
16360 context->Global()->Set(v8_str("P"), templ->NewInstance());
16362 // This compile will get the code from the compilation cache.
16363 CompileRun(source);
16365 script = v8_compile("new C1();");
16366 for (int i = 0; i < 10; i++) {
16367 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16368 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16369 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16373 v8::Isolate* gc_callbacks_isolate = NULL;
16374 int prologue_call_count = 0;
16375 int epilogue_call_count = 0;
16376 int prologue_call_count_second = 0;
16377 int epilogue_call_count_second = 0;
16378 int prologue_call_count_alloc = 0;
16379 int epilogue_call_count_alloc = 0;
16381 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16382 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16383 ++prologue_call_count;
16387 void PrologueCallback(v8::Isolate* isolate,
16389 v8::GCCallbackFlags flags) {
16390 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16391 CHECK_EQ(gc_callbacks_isolate, isolate);
16392 ++prologue_call_count;
16396 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16397 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16398 ++epilogue_call_count;
16402 void EpilogueCallback(v8::Isolate* isolate,
16404 v8::GCCallbackFlags flags) {
16405 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16406 CHECK_EQ(gc_callbacks_isolate, isolate);
16407 ++epilogue_call_count;
16411 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
16412 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16413 ++prologue_call_count_second;
16417 void PrologueCallbackSecond(v8::Isolate* isolate,
16419 v8::GCCallbackFlags flags) {
16420 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16421 CHECK_EQ(gc_callbacks_isolate, isolate);
16422 ++prologue_call_count_second;
16426 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
16427 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16428 ++epilogue_call_count_second;
16432 void EpilogueCallbackSecond(v8::Isolate* isolate,
16434 v8::GCCallbackFlags flags) {
16435 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16436 CHECK_EQ(gc_callbacks_isolate, isolate);
16437 ++epilogue_call_count_second;
16441 void PrologueCallbackAlloc(v8::Isolate* isolate,
16443 v8::GCCallbackFlags flags) {
16444 v8::HandleScope scope(isolate);
16446 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16447 CHECK_EQ(gc_callbacks_isolate, isolate);
16448 ++prologue_call_count_alloc;
16450 // Simulate full heap to see if we will reenter this callback
16451 SimulateFullSpace(CcTest::heap()->new_space());
16453 Local<Object> obj = Object::New(isolate);
16454 CHECK(!obj.IsEmpty());
16456 CcTest::heap()->CollectAllGarbage(
16457 i::Heap::kAbortIncrementalMarkingMask);
16461 void EpilogueCallbackAlloc(v8::Isolate* isolate,
16463 v8::GCCallbackFlags flags) {
16464 v8::HandleScope scope(isolate);
16466 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16467 CHECK_EQ(gc_callbacks_isolate, isolate);
16468 ++epilogue_call_count_alloc;
16470 // Simulate full heap to see if we will reenter this callback
16471 SimulateFullSpace(CcTest::heap()->new_space());
16473 Local<Object> obj = Object::New(isolate);
16474 CHECK(!obj.IsEmpty());
16476 CcTest::heap()->CollectAllGarbage(
16477 i::Heap::kAbortIncrementalMarkingMask);
16481 TEST(GCCallbacksOld) {
16482 LocalContext context;
16484 v8::V8::AddGCPrologueCallback(PrologueCallback);
16485 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
16486 CHECK_EQ(0, prologue_call_count);
16487 CHECK_EQ(0, epilogue_call_count);
16488 CcTest::heap()->CollectAllGarbage();
16489 CHECK_EQ(1, prologue_call_count);
16490 CHECK_EQ(1, epilogue_call_count);
16491 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
16492 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
16493 CcTest::heap()->CollectAllGarbage();
16494 CHECK_EQ(2, prologue_call_count);
16495 CHECK_EQ(2, epilogue_call_count);
16496 CHECK_EQ(1, prologue_call_count_second);
16497 CHECK_EQ(1, epilogue_call_count_second);
16498 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
16499 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
16500 CcTest::heap()->CollectAllGarbage();
16501 CHECK_EQ(2, prologue_call_count);
16502 CHECK_EQ(2, epilogue_call_count);
16503 CHECK_EQ(2, prologue_call_count_second);
16504 CHECK_EQ(2, epilogue_call_count_second);
16505 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
16506 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
16507 CcTest::heap()->CollectAllGarbage();
16508 CHECK_EQ(2, prologue_call_count);
16509 CHECK_EQ(2, epilogue_call_count);
16510 CHECK_EQ(2, prologue_call_count_second);
16511 CHECK_EQ(2, epilogue_call_count_second);
16515 TEST(GCCallbacks) {
16516 LocalContext context;
16517 v8::Isolate* isolate = context->GetIsolate();
16518 gc_callbacks_isolate = isolate;
16519 isolate->AddGCPrologueCallback(PrologueCallback);
16520 isolate->AddGCEpilogueCallback(EpilogueCallback);
16521 CHECK_EQ(0, prologue_call_count);
16522 CHECK_EQ(0, epilogue_call_count);
16523 CcTest::heap()->CollectAllGarbage();
16524 CHECK_EQ(1, prologue_call_count);
16525 CHECK_EQ(1, epilogue_call_count);
16526 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
16527 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
16528 CcTest::heap()->CollectAllGarbage();
16529 CHECK_EQ(2, prologue_call_count);
16530 CHECK_EQ(2, epilogue_call_count);
16531 CHECK_EQ(1, prologue_call_count_second);
16532 CHECK_EQ(1, epilogue_call_count_second);
16533 isolate->RemoveGCPrologueCallback(PrologueCallback);
16534 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
16535 CcTest::heap()->CollectAllGarbage();
16536 CHECK_EQ(2, prologue_call_count);
16537 CHECK_EQ(2, epilogue_call_count);
16538 CHECK_EQ(2, prologue_call_count_second);
16539 CHECK_EQ(2, epilogue_call_count_second);
16540 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
16541 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
16542 CcTest::heap()->CollectAllGarbage();
16543 CHECK_EQ(2, prologue_call_count);
16544 CHECK_EQ(2, epilogue_call_count);
16545 CHECK_EQ(2, prologue_call_count_second);
16546 CHECK_EQ(2, epilogue_call_count_second);
16548 CHECK_EQ(0, prologue_call_count_alloc);
16549 CHECK_EQ(0, epilogue_call_count_alloc);
16550 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
16551 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
16552 CcTest::heap()->CollectAllGarbage(
16553 i::Heap::kAbortIncrementalMarkingMask);
16554 CHECK_EQ(1, prologue_call_count_alloc);
16555 CHECK_EQ(1, epilogue_call_count_alloc);
16556 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
16557 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
16561 THREADED_TEST(AddToJSFunctionResultCache) {
16562 i::FLAG_stress_compaction = false;
16563 i::FLAG_allow_natives_syntax = true;
16564 v8::HandleScope scope(CcTest::isolate());
16566 LocalContext context;
16572 " var r0 = %_GetFromCache(0, key0);"
16573 " var r1 = %_GetFromCache(0, key1);"
16574 " var r0_ = %_GetFromCache(0, key0);"
16576 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
16577 " var r1_ = %_GetFromCache(0, key1);"
16579 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
16580 " return 'PASSED';"
16582 CcTest::heap()->ClearJSFunctionResultCaches();
16583 ExpectString(code, "PASSED");
16587 THREADED_TEST(FillJSFunctionResultCache) {
16588 i::FLAG_allow_natives_syntax = true;
16589 LocalContext context;
16590 v8::HandleScope scope(context->GetIsolate());
16595 " var r = %_GetFromCache(0, k);"
16596 " for (var i = 0; i < 16; i++) {"
16597 " %_GetFromCache(0, 'a' + i);"
16599 " if (r === %_GetFromCache(0, k))"
16600 " return 'FAILED: k0CacheSize is too small';"
16601 " return 'PASSED';"
16603 CcTest::heap()->ClearJSFunctionResultCaches();
16604 ExpectString(code, "PASSED");
16608 THREADED_TEST(RoundRobinGetFromCache) {
16609 i::FLAG_allow_natives_syntax = true;
16610 LocalContext context;
16611 v8::HandleScope scope(context->GetIsolate());
16616 " for (var i = 0; i < 16; i++) keys.push(i);"
16617 " var values = [];"
16618 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
16619 " for (var i = 0; i < 16; i++) {"
16620 " var v = %_GetFromCache(0, keys[i]);"
16621 " if (v.toString() !== values[i].toString())"
16622 " return 'Wrong value for ' + "
16623 " keys[i] + ': ' + v + ' vs. ' + values[i];"
16625 " return 'PASSED';"
16627 CcTest::heap()->ClearJSFunctionResultCaches();
16628 ExpectString(code, "PASSED");
16632 THREADED_TEST(ReverseGetFromCache) {
16633 i::FLAG_allow_natives_syntax = true;
16634 LocalContext context;
16635 v8::HandleScope scope(context->GetIsolate());
16640 " for (var i = 0; i < 16; i++) keys.push(i);"
16641 " var values = [];"
16642 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
16643 " for (var i = 15; i >= 16; i--) {"
16644 " var v = %_GetFromCache(0, keys[i]);"
16645 " if (v !== values[i])"
16646 " return 'Wrong value for ' + "
16647 " keys[i] + ': ' + v + ' vs. ' + values[i];"
16649 " return 'PASSED';"
16651 CcTest::heap()->ClearJSFunctionResultCaches();
16652 ExpectString(code, "PASSED");
16656 THREADED_TEST(TestEviction) {
16657 i::FLAG_allow_natives_syntax = true;
16658 LocalContext context;
16659 v8::HandleScope scope(context->GetIsolate());
16663 " for (var i = 0; i < 2*16; i++) {"
16664 " %_GetFromCache(0, 'a' + i);"
16666 " return 'PASSED';"
16668 CcTest::heap()->ClearJSFunctionResultCaches();
16669 ExpectString(code, "PASSED");
16673 THREADED_TEST(TwoByteStringInOneByteCons) {
16674 // See Chromium issue 47824.
16675 LocalContext context;
16676 v8::HandleScope scope(context->GetIsolate());
16678 const char* init_code =
16679 "var str1 = 'abelspendabel';"
16680 "var str2 = str1 + str1 + str1;"
16682 Local<Value> result = CompileRun(init_code);
16684 Local<Value> indexof = CompileRun("str2.indexOf('els')");
16685 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
16687 CHECK(result->IsString());
16688 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
16689 int length = string->length();
16690 CHECK(string->IsOneByteRepresentation());
16692 i::Handle<i::String> flat_string = i::String::Flatten(string);
16694 CHECK(string->IsOneByteRepresentation());
16695 CHECK(flat_string->IsOneByteRepresentation());
16697 // Create external resource.
16698 uint16_t* uc16_buffer = new uint16_t[length + 1];
16700 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
16701 uc16_buffer[length] = 0;
16703 TestResource resource(uc16_buffer);
16705 flat_string->MakeExternal(&resource);
16707 CHECK(flat_string->IsTwoByteRepresentation());
16709 // If the cons string has been short-circuited, skip the following checks.
16710 if (!string.is_identical_to(flat_string)) {
16711 // At this point, we should have a Cons string which is flat and one-byte,
16712 // with a first half that is a two-byte string (although it only contains
16713 // one-byte characters). This is a valid sequence of steps, and it can
16714 // happen in real pages.
16715 CHECK(string->IsOneByteRepresentation());
16716 i::ConsString* cons = i::ConsString::cast(*string);
16717 CHECK_EQ(0, cons->second()->length());
16718 CHECK(cons->first()->IsTwoByteRepresentation());
16721 // Check that some string operations work.
16724 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
16725 CHECK_EQ(6, reresult->Int32Value());
16728 reresult = CompileRun("str2.match(/abe./g).length;");
16729 CHECK_EQ(6, reresult->Int32Value());
16731 reresult = CompileRun("str2.search(/bel/g);");
16732 CHECK_EQ(1, reresult->Int32Value());
16734 reresult = CompileRun("str2.search(/be./g);");
16735 CHECK_EQ(1, reresult->Int32Value());
16737 ExpectTrue("/bel/g.test(str2);");
16739 ExpectTrue("/be./g.test(str2);");
16741 reresult = CompileRun("/bel/g.exec(str2);");
16742 CHECK(!reresult->IsNull());
16744 reresult = CompileRun("/be./g.exec(str2);");
16745 CHECK(!reresult->IsNull());
16747 ExpectString("str2.substring(2, 10);", "elspenda");
16749 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
16751 ExpectString("str2.charAt(2);", "e");
16753 ExpectObject("str2.indexOf('els');", indexof);
16755 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
16757 reresult = CompileRun("str2.charCodeAt(2);");
16758 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
16762 TEST(ContainsOnlyOneByte) {
16763 v8::V8::Initialize();
16764 v8::Isolate* isolate = CcTest::isolate();
16765 v8::HandleScope scope(isolate);
16766 // Make a buffer long enough that it won't automatically be converted.
16767 const int length = 512;
16768 // Ensure word aligned assignment.
16769 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
16770 i::SmartArrayPointer<uintptr_t>
16771 aligned_contents(new uintptr_t[aligned_length]);
16772 uint16_t* string_contents =
16773 reinterpret_cast<uint16_t*>(aligned_contents.get());
16774 // Set to contain only one byte.
16775 for (int i = 0; i < length-1; i++) {
16776 string_contents[i] = 0x41;
16778 string_contents[length-1] = 0;
16780 Handle<String> string =
16781 String::NewExternal(isolate,
16782 new TestResource(string_contents, NULL, false));
16783 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
16784 // Counter example.
16785 string = String::NewFromTwoByte(isolate, string_contents);
16786 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
16787 // Test left right and balanced cons strings.
16788 Handle<String> base = String::NewFromUtf8(isolate, "a");
16789 Handle<String> left = base;
16790 Handle<String> right = base;
16791 for (int i = 0; i < 1000; i++) {
16792 left = String::Concat(base, left);
16793 right = String::Concat(right, base);
16795 Handle<String> balanced = String::Concat(left, base);
16796 balanced = String::Concat(balanced, right);
16797 Handle<String> cons_strings[] = {left, balanced, right};
16798 Handle<String> two_byte =
16799 String::NewExternal(isolate,
16800 new TestResource(string_contents, NULL, false));
16801 USE(two_byte); USE(cons_strings);
16802 for (size_t i = 0; i < arraysize(cons_strings); i++) {
16803 // Base assumptions.
16804 string = cons_strings[i];
16805 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
16806 // Test left and right concatentation.
16807 string = String::Concat(two_byte, cons_strings[i]);
16808 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
16809 string = String::Concat(cons_strings[i], two_byte);
16810 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
16812 // Set bits in different positions
16813 // for strings of different lengths and alignments.
16814 for (int alignment = 0; alignment < 7; alignment++) {
16815 for (int size = 2; alignment + size < length; size *= 2) {
16816 int zero_offset = size + alignment;
16817 string_contents[zero_offset] = 0;
16818 for (int i = 0; i < size; i++) {
16819 int shift = 8 + (i % 7);
16820 string_contents[alignment + i] = 1 << shift;
16821 string = String::NewExternal(
16823 new TestResource(string_contents + alignment, NULL, false));
16824 CHECK_EQ(size, string->Length());
16825 CHECK(!string->ContainsOnlyOneByte());
16826 string_contents[alignment + i] = 0x41;
16828 string_contents[zero_offset] = 0x41;
16834 // Failed access check callback that performs a GC on each invocation.
16835 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
16836 v8::AccessType type,
16837 Local<v8::Value> data) {
16838 CcTest::heap()->CollectAllGarbage();
16839 CcTest::isolate()->ThrowException(
16840 v8::Exception::Error(v8_str("cross context")));
16844 TEST(GCInFailedAccessCheckCallback) {
16845 // Install a failed access check callback that performs a GC on each
16846 // invocation. Then force the callback to be called from va
16848 v8::V8::Initialize();
16849 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
16851 v8::Isolate* isolate = CcTest::isolate();
16852 v8::HandleScope scope(isolate);
16854 // Create an ObjectTemplate for global objects and install access
16855 // check callbacks that will block access.
16856 v8::Handle<v8::ObjectTemplate> global_template =
16857 v8::ObjectTemplate::New(isolate);
16858 global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL,
16859 v8::Handle<v8::Value>());
16861 // Create a context and set an x property on it's global object.
16862 LocalContext context0(NULL, global_template);
16863 context0->Global()->Set(v8_str("x"), v8_num(42));
16864 v8::Handle<v8::Object> global0 = context0->Global();
16866 // Create a context with a different security token so that the
16867 // failed access check callback will be called on each access.
16868 LocalContext context1(NULL, global_template);
16869 context1->Global()->Set(v8_str("other"), global0);
16871 v8::TryCatch try_catch(isolate);
16873 // Get property with failed access check.
16874 CHECK(CompileRun("other.x").IsEmpty());
16875 CHECK(try_catch.HasCaught());
16878 // Get element with failed access check.
16879 CHECK(CompileRun("other[0]").IsEmpty());
16880 CHECK(try_catch.HasCaught());
16883 // Set property with failed access check.
16884 CHECK(CompileRun("other.x = new Object()").IsEmpty());
16885 CHECK(try_catch.HasCaught());
16888 // Set element with failed access check.
16889 CHECK(CompileRun("other[0] = new Object()").IsEmpty());
16890 CHECK(try_catch.HasCaught());
16893 // Get property attribute with failed access check.
16894 CHECK(CompileRun("\'x\' in other").IsEmpty());
16895 CHECK(try_catch.HasCaught());
16898 // Get property attribute for element with failed access check.
16899 CHECK(CompileRun("0 in other").IsEmpty());
16900 CHECK(try_catch.HasCaught());
16903 // Delete property.
16904 CHECK(CompileRun("delete other.x").IsEmpty());
16905 CHECK(try_catch.HasCaught());
16909 CHECK_EQ(false, global0->Delete(0));
16913 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
16915 // Define JavaScript accessor.
16917 "Object.prototype.__defineGetter__.call("
16918 " other, \'x\', function() { return 42; })").IsEmpty());
16919 CHECK(try_catch.HasCaught());
16924 "Object.prototype.__lookupGetter__.call("
16925 " other, \'x\')").IsEmpty());
16926 CHECK(try_catch.HasCaught());
16931 "Object.prototype.hasOwnProperty.call("
16932 "other, \'0\')").IsEmpty());
16933 CHECK(try_catch.HasCaught());
16936 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
16937 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
16938 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
16940 // Reset the failed access check callback so it does not influence
16941 // the other tests.
16942 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
16946 TEST(IsolateNewDispose) {
16947 v8::Isolate* current_isolate = CcTest::isolate();
16948 v8::Isolate::CreateParams create_params;
16949 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
16950 v8::Isolate* isolate = v8::Isolate::New(create_params);
16951 CHECK(isolate != NULL);
16952 CHECK(current_isolate != isolate);
16953 CHECK(current_isolate == CcTest::isolate());
16955 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16956 last_location = last_message = NULL;
16957 isolate->Dispose();
16958 CHECK(!last_location);
16959 CHECK(!last_message);
16963 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
16964 v8::Isolate::CreateParams create_params;
16965 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
16966 v8::Isolate* isolate = v8::Isolate::New(create_params);
16968 v8::Isolate::Scope i_scope(isolate);
16969 v8::HandleScope scope(isolate);
16970 LocalContext context(isolate);
16971 // Run something in this isolate.
16972 ExpectTrue("true");
16973 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
16974 last_location = last_message = NULL;
16975 // Still entered, should fail.
16976 isolate->Dispose();
16977 CHECK(last_location);
16978 CHECK(last_message);
16980 isolate->Dispose();
16984 static void BreakArrayGuarantees(const char* script) {
16985 v8::Isolate::CreateParams create_params;
16986 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
16987 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
16989 v8::Persistent<v8::Context> context1;
16991 v8::HandleScope scope(isolate1);
16992 context1.Reset(isolate1, Context::New(isolate1));
16996 v8::HandleScope scope(isolate1);
16997 v8::Local<v8::Context> context =
16998 v8::Local<v8::Context>::New(isolate1, context1);
16999 v8::Context::Scope context_scope(context);
17000 v8::internal::Isolate* i_isolate =
17001 reinterpret_cast<v8::internal::Isolate*>(isolate1);
17002 CHECK_EQ(true, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
17003 // Run something in new isolate.
17004 CompileRun(script);
17005 CHECK_EQ(false, i_isolate->IsFastArrayConstructorPrototypeChainIntact());
17008 isolate1->Dispose();
17012 TEST(VerifyArrayPrototypeGuarantees) {
17013 // Break fast array hole handling by element changes.
17014 BreakArrayGuarantees("[].__proto__[1] = 3;");
17015 BreakArrayGuarantees("Object.prototype[3] = 'three';");
17016 BreakArrayGuarantees("Array.prototype.push(1);");
17017 BreakArrayGuarantees("Array.prototype.unshift(1);");
17018 // Break fast array hole handling by changing length.
17019 BreakArrayGuarantees("Array.prototype.length = 30;");
17020 // Break fast array hole handling by prototype structure changes.
17021 BreakArrayGuarantees("[].__proto__.__proto__ = { funny: true };");
17022 // By sending elements to dictionary mode.
17023 BreakArrayGuarantees("Object.freeze(Array.prototype);");
17024 BreakArrayGuarantees("Object.freeze(Object.prototype);");
17025 BreakArrayGuarantees(
17026 "Object.defineProperty(Array.prototype, 0, {"
17027 " get: function() { return 3; }});");
17028 BreakArrayGuarantees(
17029 "Object.defineProperty(Object.prototype, 0, {"
17030 " get: function() { return 3; }});");
17034 TEST(RunTwoIsolatesOnSingleThread) {
17036 v8::Isolate::CreateParams create_params;
17037 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17038 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
17040 v8::Persistent<v8::Context> context1;
17042 v8::HandleScope scope(isolate1);
17043 context1.Reset(isolate1, Context::New(isolate1));
17047 v8::HandleScope scope(isolate1);
17048 v8::Local<v8::Context> context =
17049 v8::Local<v8::Context>::New(isolate1, context1);
17050 v8::Context::Scope context_scope(context);
17051 // Run something in new isolate.
17052 CompileRun("var foo = 'isolate 1';");
17053 ExpectString("function f() { return foo; }; f()", "isolate 1");
17057 v8::Isolate* isolate2 = v8::Isolate::New(create_params);
17058 v8::Persistent<v8::Context> context2;
17061 v8::Isolate::Scope iscope(isolate2);
17062 v8::HandleScope scope(isolate2);
17063 context2.Reset(isolate2, Context::New(isolate2));
17064 v8::Local<v8::Context> context =
17065 v8::Local<v8::Context>::New(isolate2, context2);
17066 v8::Context::Scope context_scope(context);
17068 // Run something in new isolate.
17069 CompileRun("var foo = 'isolate 2';");
17070 ExpectString("function f() { return foo; }; f()", "isolate 2");
17074 v8::HandleScope scope(isolate1);
17075 v8::Local<v8::Context> context =
17076 v8::Local<v8::Context>::New(isolate1, context1);
17077 v8::Context::Scope context_scope(context);
17078 // Now again in isolate 1
17079 ExpectString("function f() { return foo; }; f()", "isolate 1");
17084 // Run some stuff in default isolate.
17085 v8::Persistent<v8::Context> context_default;
17087 v8::Isolate* isolate = CcTest::isolate();
17088 v8::Isolate::Scope iscope(isolate);
17089 v8::HandleScope scope(isolate);
17090 context_default.Reset(isolate, Context::New(isolate));
17094 v8::HandleScope scope(CcTest::isolate());
17095 v8::Local<v8::Context> context =
17096 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17097 v8::Context::Scope context_scope(context);
17098 // Variables in other isolates should be not available, verify there
17099 // is an exception.
17100 ExpectTrue("function f() {"
17108 "var isDefaultIsolate = true;"
17115 v8::Isolate::Scope iscope(isolate2);
17116 v8::HandleScope scope(isolate2);
17117 v8::Local<v8::Context> context =
17118 v8::Local<v8::Context>::New(isolate2, context2);
17119 v8::Context::Scope context_scope(context);
17120 ExpectString("function f() { return foo; }; f()", "isolate 2");
17124 v8::HandleScope scope(v8::Isolate::GetCurrent());
17125 v8::Local<v8::Context> context =
17126 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
17127 v8::Context::Scope context_scope(context);
17128 ExpectString("function f() { return foo; }; f()", "isolate 1");
17132 v8::Isolate::Scope iscope(isolate2);
17139 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17140 last_location = last_message = NULL;
17142 isolate1->Dispose();
17143 CHECK(!last_location);
17144 CHECK(!last_message);
17146 isolate2->Dispose();
17147 CHECK(!last_location);
17148 CHECK(!last_message);
17150 // Check that default isolate still runs.
17152 v8::HandleScope scope(CcTest::isolate());
17153 v8::Local<v8::Context> context =
17154 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17155 v8::Context::Scope context_scope(context);
17156 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
17161 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
17162 v8::Isolate::Scope isolate_scope(isolate);
17163 v8::HandleScope scope(isolate);
17164 LocalContext context(isolate);
17165 i::ScopedVector<char> code(1024);
17166 i::SNPrintF(code, "function fib(n) {"
17167 " if (n <= 2) return 1;"
17168 " return fib(n-1) + fib(n-2);"
17171 Local<Value> value = CompileRun(code.start());
17172 CHECK(value->IsNumber());
17173 return static_cast<int>(value->NumberValue());
17176 class IsolateThread : public v8::base::Thread {
17178 explicit IsolateThread(int fib_limit)
17179 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
17182 v8::Isolate::CreateParams create_params;
17183 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17184 v8::Isolate* isolate = v8::Isolate::New(create_params);
17185 result_ = CalcFibonacci(isolate, fib_limit_);
17186 isolate->Dispose();
17189 int result() { return result_; }
17197 TEST(MultipleIsolatesOnIndividualThreads) {
17198 IsolateThread thread1(21);
17199 IsolateThread thread2(12);
17201 // Compute some fibonacci numbers on 3 threads in 3 isolates.
17205 int result1 = CalcFibonacci(CcTest::isolate(), 21);
17206 int result2 = CalcFibonacci(CcTest::isolate(), 12);
17211 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
17212 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
17213 CHECK_EQ(result1, 10946);
17214 CHECK_EQ(result2, 144);
17215 CHECK_EQ(result1, thread1.result());
17216 CHECK_EQ(result2, thread2.result());
17220 TEST(IsolateDifferentContexts) {
17221 v8::Isolate::CreateParams create_params;
17222 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17223 v8::Isolate* isolate = v8::Isolate::New(create_params);
17224 Local<v8::Context> context;
17226 v8::Isolate::Scope isolate_scope(isolate);
17227 v8::HandleScope handle_scope(isolate);
17228 context = v8::Context::New(isolate);
17229 v8::Context::Scope context_scope(context);
17230 Local<Value> v = CompileRun("2");
17231 CHECK(v->IsNumber());
17232 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
17235 v8::Isolate::Scope isolate_scope(isolate);
17236 v8::HandleScope handle_scope(isolate);
17237 context = v8::Context::New(isolate);
17238 v8::Context::Scope context_scope(context);
17239 Local<Value> v = CompileRun("22");
17240 CHECK(v->IsNumber());
17241 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
17243 isolate->Dispose();
17246 class InitDefaultIsolateThread : public v8::base::Thread {
17249 SetResourceConstraints,
17251 SetCounterFunction,
17252 SetCreateHistogramFunction,
17253 SetAddHistogramSampleFunction
17256 explicit InitDefaultIsolateThread(TestCase testCase)
17257 : Thread(Options("InitDefaultIsolateThread")),
17258 testCase_(testCase),
17262 v8::Isolate::CreateParams create_params;
17263 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
17264 switch (testCase_) {
17265 case SetResourceConstraints: {
17266 create_params.constraints.set_max_semi_space_size(1);
17267 create_params.constraints.set_max_old_space_size(4);
17273 v8::Isolate* isolate = v8::Isolate::New(create_params);
17275 switch (testCase_) {
17276 case SetResourceConstraints:
17277 // Already handled in pre-Isolate-creation block.
17280 case SetFatalHandler:
17281 v8::V8::SetFatalErrorHandler(NULL);
17284 case SetCounterFunction:
17285 CcTest::isolate()->SetCounterFunction(NULL);
17288 case SetCreateHistogramFunction:
17289 CcTest::isolate()->SetCreateHistogramFunction(NULL);
17292 case SetAddHistogramSampleFunction:
17293 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
17297 isolate->Dispose();
17301 bool result() { return result_; }
17304 TestCase testCase_;
17309 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
17310 InitDefaultIsolateThread thread(testCase);
17313 CHECK_EQ(thread.result(), true);
17317 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
17318 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
17322 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
17323 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
17327 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
17328 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
17332 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
17333 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
17337 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
17338 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
17342 TEST(StringCheckMultipleContexts) {
17344 "(function() { return \"a\".charAt(0); })()";
17347 // Run the code twice in the first context to initialize the call IC.
17348 LocalContext context1;
17349 v8::HandleScope scope(context1->GetIsolate());
17350 ExpectString(code, "a");
17351 ExpectString(code, "a");
17355 // Change the String.prototype in the second context and check
17356 // that the right function gets called.
17357 LocalContext context2;
17358 v8::HandleScope scope(context2->GetIsolate());
17359 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
17360 ExpectString(code, "not a");
17365 TEST(NumberCheckMultipleContexts) {
17367 "(function() { return (42).toString(); })()";
17370 // Run the code twice in the first context to initialize the call IC.
17371 LocalContext context1;
17372 v8::HandleScope scope(context1->GetIsolate());
17373 ExpectString(code, "42");
17374 ExpectString(code, "42");
17378 // Change the Number.prototype in the second context and check
17379 // that the right function gets called.
17380 LocalContext context2;
17381 v8::HandleScope scope(context2->GetIsolate());
17382 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
17383 ExpectString(code, "not 42");
17388 TEST(BooleanCheckMultipleContexts) {
17390 "(function() { return true.toString(); })()";
17393 // Run the code twice in the first context to initialize the call IC.
17394 LocalContext context1;
17395 v8::HandleScope scope(context1->GetIsolate());
17396 ExpectString(code, "true");
17397 ExpectString(code, "true");
17401 // Change the Boolean.prototype in the second context and check
17402 // that the right function gets called.
17403 LocalContext context2;
17404 v8::HandleScope scope(context2->GetIsolate());
17405 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
17406 ExpectString(code, "");
17411 TEST(DontDeleteCellLoadIC) {
17412 const char* function_code =
17413 "function readCell() { while (true) { return cell; } }";
17416 // Run the code twice in the first context to initialize the load
17417 // IC for a don't delete cell.
17418 LocalContext context1;
17419 v8::HandleScope scope(context1->GetIsolate());
17420 CompileRun("var cell = \"first\";");
17421 ExpectBoolean("delete cell", false);
17422 CompileRun(function_code);
17423 ExpectString("readCell()", "first");
17424 ExpectString("readCell()", "first");
17428 // Use a deletable cell in the second context.
17429 LocalContext context2;
17430 v8::HandleScope scope(context2->GetIsolate());
17431 CompileRun("cell = \"second\";");
17432 CompileRun(function_code);
17433 ExpectString("readCell()", "second");
17434 ExpectBoolean("delete cell", true);
17435 ExpectString("(function() {"
17437 " return readCell();"
17439 " return e.toString();"
17442 "ReferenceError: cell is not defined");
17443 CompileRun("cell = \"new_second\";");
17444 CcTest::heap()->CollectAllGarbage();
17445 ExpectString("readCell()", "new_second");
17446 ExpectString("readCell()", "new_second");
17451 class Visitor42 : public v8::PersistentHandleVisitor {
17453 explicit Visitor42(v8::Persistent<v8::Object>* object)
17454 : counter_(0), object_(object) { }
17456 virtual void VisitPersistentHandle(Persistent<Value>* value,
17457 uint16_t class_id) {
17458 if (class_id != 42) return;
17459 CHECK_EQ(42, value->WrapperClassId());
17460 v8::Isolate* isolate = CcTest::isolate();
17461 v8::HandleScope handle_scope(isolate);
17462 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
17463 v8::Handle<v8::Value> object =
17464 v8::Local<v8::Object>::New(isolate, *object_);
17465 CHECK(handle->IsObject());
17466 CHECK(Handle<Object>::Cast(handle)->Equals(object));
17471 v8::Persistent<v8::Object>* object_;
17475 TEST(PersistentHandleVisitor) {
17476 LocalContext context;
17477 v8::Isolate* isolate = context->GetIsolate();
17478 v8::HandleScope scope(isolate);
17479 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17480 CHECK_EQ(0, object.WrapperClassId());
17481 object.SetWrapperClassId(42);
17482 CHECK_EQ(42, object.WrapperClassId());
17484 Visitor42 visitor(&object);
17485 v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
17486 CHECK_EQ(1, visitor.counter_);
17492 TEST(WrapperClassId) {
17493 LocalContext context;
17494 v8::Isolate* isolate = context->GetIsolate();
17495 v8::HandleScope scope(isolate);
17496 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17497 CHECK_EQ(0, object.WrapperClassId());
17498 object.SetWrapperClassId(65535);
17499 CHECK_EQ(65535, object.WrapperClassId());
17504 TEST(PersistentHandleInNewSpaceVisitor) {
17505 LocalContext context;
17506 v8::Isolate* isolate = context->GetIsolate();
17507 v8::HandleScope scope(isolate);
17508 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
17509 CHECK_EQ(0, object1.WrapperClassId());
17510 object1.SetWrapperClassId(42);
17511 CHECK_EQ(42, object1.WrapperClassId());
17513 CcTest::heap()->CollectAllGarbage();
17514 CcTest::heap()->CollectAllGarbage();
17516 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
17517 CHECK_EQ(0, object2.WrapperClassId());
17518 object2.SetWrapperClassId(42);
17519 CHECK_EQ(42, object2.WrapperClassId());
17521 Visitor42 visitor(&object2);
17522 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
17523 CHECK_EQ(1, visitor.counter_);
17531 LocalContext context;
17532 v8::HandleScope scope(context->GetIsolate());
17534 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
17535 CHECK(re->IsRegExp());
17536 CHECK(re->GetSource()->Equals(v8_str("foo")));
17537 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
17539 re = v8::RegExp::New(v8_str("bar"),
17540 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
17541 v8::RegExp::kGlobal));
17542 CHECK(re->IsRegExp());
17543 CHECK(re->GetSource()->Equals(v8_str("bar")));
17544 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
17545 static_cast<int>(re->GetFlags()));
17547 re = v8::RegExp::New(v8_str("baz"),
17548 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
17549 v8::RegExp::kMultiline));
17550 CHECK(re->IsRegExp());
17551 CHECK(re->GetSource()->Equals(v8_str("baz")));
17552 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
17553 static_cast<int>(re->GetFlags()));
17555 re = CompileRun("/quux/").As<v8::RegExp>();
17556 CHECK(re->IsRegExp());
17557 CHECK(re->GetSource()->Equals(v8_str("quux")));
17558 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
17560 re = CompileRun("/quux/gm").As<v8::RegExp>();
17561 CHECK(re->IsRegExp());
17562 CHECK(re->GetSource()->Equals(v8_str("quux")));
17563 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
17564 static_cast<int>(re->GetFlags()));
17566 // Override the RegExp constructor and check the API constructor
17568 CompileRun("RegExp = function() {}");
17570 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
17571 CHECK(re->IsRegExp());
17572 CHECK(re->GetSource()->Equals(v8_str("foobar")));
17573 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
17575 re = v8::RegExp::New(v8_str("foobarbaz"),
17576 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
17577 v8::RegExp::kMultiline));
17578 CHECK(re->IsRegExp());
17579 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
17580 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
17581 static_cast<int>(re->GetFlags()));
17583 context->Global()->Set(v8_str("re"), re);
17584 ExpectTrue("re.test('FoobarbaZ')");
17586 // RegExps are objects on which you can set properties.
17587 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
17588 v8::Handle<v8::Value> value(CompileRun("re.property"));
17589 CHECK_EQ(32, value->Int32Value());
17591 v8::TryCatch try_catch(context->GetIsolate());
17592 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
17593 CHECK(re.IsEmpty());
17594 CHECK(try_catch.HasCaught());
17595 context->Global()->Set(v8_str("ex"), try_catch.Exception());
17596 ExpectTrue("ex instanceof SyntaxError");
17600 THREADED_TEST(Equals) {
17601 LocalContext localContext;
17602 v8::HandleScope handleScope(localContext->GetIsolate());
17604 v8::Handle<v8::Object> globalProxy = localContext->Global();
17605 v8::Handle<Value> global = globalProxy->GetPrototype();
17607 CHECK(global->StrictEquals(global));
17608 CHECK(!global->StrictEquals(globalProxy));
17609 CHECK(!globalProxy->StrictEquals(global));
17610 CHECK(globalProxy->StrictEquals(globalProxy));
17612 CHECK(global->Equals(global));
17613 CHECK(!global->Equals(globalProxy));
17614 CHECK(!globalProxy->Equals(global));
17615 CHECK(globalProxy->Equals(globalProxy));
17619 static void Getter(v8::Local<v8::Name> property,
17620 const v8::PropertyCallbackInfo<v8::Value>& info) {
17621 info.GetReturnValue().Set(v8_str("42!"));
17625 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
17626 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
17627 result->Set(0, v8_str("universalAnswer"));
17628 info.GetReturnValue().Set(result);
17632 TEST(NamedEnumeratorAndForIn) {
17633 LocalContext context;
17634 v8::Isolate* isolate = context->GetIsolate();
17635 v8::HandleScope handle_scope(isolate);
17636 v8::Context::Scope context_scope(context.local());
17638 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
17639 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
17640 NULL, Enumerator));
17641 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
17642 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
17643 "var result = []; for (var k in o) result.push(k); result"));
17644 CHECK_EQ(1u, result->Length());
17645 CHECK(v8_str("universalAnswer")->Equals(result->Get(0)));
17649 TEST(DefinePropertyPostDetach) {
17650 LocalContext context;
17651 v8::HandleScope scope(context->GetIsolate());
17652 v8::Handle<v8::Object> proxy = context->Global();
17653 v8::Handle<v8::Function> define_property =
17654 CompileRun("(function() {"
17655 " Object.defineProperty("
17658 " { configurable: true, enumerable: true, value: 3 });"
17659 "})").As<Function>();
17660 context->DetachGlobal();
17661 define_property->Call(proxy, 0, NULL);
17665 static void InstallContextId(v8::Handle<Context> context, int id) {
17666 Context::Scope scope(context);
17667 CompileRun("Object.prototype").As<Object>()->
17668 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
17672 static void CheckContextId(v8::Handle<Object> object, int expected) {
17673 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
17677 THREADED_TEST(CreationContext) {
17678 v8::Isolate* isolate = CcTest::isolate();
17679 HandleScope handle_scope(isolate);
17680 Handle<Context> context1 = Context::New(isolate);
17681 InstallContextId(context1, 1);
17682 Handle<Context> context2 = Context::New(isolate);
17683 InstallContextId(context2, 2);
17684 Handle<Context> context3 = Context::New(isolate);
17685 InstallContextId(context3, 3);
17687 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
17689 Local<Object> object1;
17690 Local<Function> func1;
17692 Context::Scope scope(context1);
17693 object1 = Object::New(isolate);
17694 func1 = tmpl->GetFunction();
17697 Local<Object> object2;
17698 Local<Function> func2;
17700 Context::Scope scope(context2);
17701 object2 = Object::New(isolate);
17702 func2 = tmpl->GetFunction();
17705 Local<Object> instance1;
17706 Local<Object> instance2;
17709 Context::Scope scope(context3);
17710 instance1 = func1->NewInstance();
17711 instance2 = func2->NewInstance();
17715 Handle<Context> other_context = Context::New(isolate);
17716 Context::Scope scope(other_context);
17717 CHECK(object1->CreationContext() == context1);
17718 CheckContextId(object1, 1);
17719 CHECK(func1->CreationContext() == context1);
17720 CheckContextId(func1, 1);
17721 CHECK(instance1->CreationContext() == context1);
17722 CheckContextId(instance1, 1);
17723 CHECK(object2->CreationContext() == context2);
17724 CheckContextId(object2, 2);
17725 CHECK(func2->CreationContext() == context2);
17726 CheckContextId(func2, 2);
17727 CHECK(instance2->CreationContext() == context2);
17728 CheckContextId(instance2, 2);
17732 Context::Scope scope(context1);
17733 CHECK(object1->CreationContext() == context1);
17734 CheckContextId(object1, 1);
17735 CHECK(func1->CreationContext() == context1);
17736 CheckContextId(func1, 1);
17737 CHECK(instance1->CreationContext() == context1);
17738 CheckContextId(instance1, 1);
17739 CHECK(object2->CreationContext() == context2);
17740 CheckContextId(object2, 2);
17741 CHECK(func2->CreationContext() == context2);
17742 CheckContextId(func2, 2);
17743 CHECK(instance2->CreationContext() == context2);
17744 CheckContextId(instance2, 2);
17748 Context::Scope scope(context2);
17749 CHECK(object1->CreationContext() == context1);
17750 CheckContextId(object1, 1);
17751 CHECK(func1->CreationContext() == context1);
17752 CheckContextId(func1, 1);
17753 CHECK(instance1->CreationContext() == context1);
17754 CheckContextId(instance1, 1);
17755 CHECK(object2->CreationContext() == context2);
17756 CheckContextId(object2, 2);
17757 CHECK(func2->CreationContext() == context2);
17758 CheckContextId(func2, 2);
17759 CHECK(instance2->CreationContext() == context2);
17760 CheckContextId(instance2, 2);
17765 THREADED_TEST(CreationContextOfJsFunction) {
17766 HandleScope handle_scope(CcTest::isolate());
17767 Handle<Context> context = Context::New(CcTest::isolate());
17768 InstallContextId(context, 1);
17770 Local<Object> function;
17772 Context::Scope scope(context);
17773 function = CompileRun("function foo() {}; foo").As<Object>();
17776 Handle<Context> other_context = Context::New(CcTest::isolate());
17777 Context::Scope scope(other_context);
17778 CHECK(function->CreationContext() == context);
17779 CheckContextId(function, 1);
17783 void HasOwnPropertyIndexedPropertyGetter(
17785 const v8::PropertyCallbackInfo<v8::Value>& info) {
17786 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
17790 void HasOwnPropertyNamedPropertyGetter(
17791 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
17792 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
17796 void HasOwnPropertyIndexedPropertyQuery(
17797 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
17798 if (index == 42) info.GetReturnValue().Set(1);
17802 void HasOwnPropertyNamedPropertyQuery(
17803 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
17804 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
17808 void HasOwnPropertyNamedPropertyQuery2(
17809 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
17810 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
17814 void HasOwnPropertyAccessorGetter(
17815 Local<String> property,
17816 const v8::PropertyCallbackInfo<v8::Value>& info) {
17817 info.GetReturnValue().Set(v8_str("yes"));
17821 TEST(HasOwnProperty) {
17823 v8::Isolate* isolate = env->GetIsolate();
17824 v8::HandleScope scope(isolate);
17825 { // Check normal properties and defined getters.
17826 Handle<Value> value = CompileRun(
17829 " this.__defineGetter__('baz', function() { return 1; });"
17831 "function Bar() { "
17833 " this.__defineGetter__('bla', function() { return 2; });"
17835 "Bar.prototype = new Foo();"
17837 CHECK(value->IsObject());
17838 Handle<Object> object = value->ToObject(isolate);
17839 CHECK(object->Has(v8_str("foo")));
17840 CHECK(!object->HasOwnProperty(v8_str("foo")));
17841 CHECK(object->HasOwnProperty(v8_str("bar")));
17842 CHECK(object->Has(v8_str("baz")));
17843 CHECK(!object->HasOwnProperty(v8_str("baz")));
17844 CHECK(object->HasOwnProperty(v8_str("bla")));
17846 { // Check named getter interceptors.
17847 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17848 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
17849 HasOwnPropertyNamedPropertyGetter));
17850 Handle<Object> instance = templ->NewInstance();
17851 CHECK(!instance->HasOwnProperty(v8_str("42")));
17852 CHECK(instance->HasOwnProperty(v8_str("foo")));
17853 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17855 { // Check indexed getter interceptors.
17856 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17857 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
17858 HasOwnPropertyIndexedPropertyGetter));
17859 Handle<Object> instance = templ->NewInstance();
17860 CHECK(instance->HasOwnProperty(v8_str("42")));
17861 CHECK(!instance->HasOwnProperty(v8_str("43")));
17862 CHECK(!instance->HasOwnProperty(v8_str("foo")));
17864 { // Check named query interceptors.
17865 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17866 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
17867 0, 0, HasOwnPropertyNamedPropertyQuery));
17868 Handle<Object> instance = templ->NewInstance();
17869 CHECK(instance->HasOwnProperty(v8_str("foo")));
17870 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17872 { // Check indexed query interceptors.
17873 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17874 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
17875 0, 0, HasOwnPropertyIndexedPropertyQuery));
17876 Handle<Object> instance = templ->NewInstance();
17877 CHECK(instance->HasOwnProperty(v8_str("42")));
17878 CHECK(!instance->HasOwnProperty(v8_str("41")));
17880 { // Check callbacks.
17881 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17882 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
17883 Handle<Object> instance = templ->NewInstance();
17884 CHECK(instance->HasOwnProperty(v8_str("foo")));
17885 CHECK(!instance->HasOwnProperty(v8_str("bar")));
17887 { // Check that query wins on disagreement.
17888 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17889 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
17890 HasOwnPropertyNamedPropertyGetter, 0,
17891 HasOwnPropertyNamedPropertyQuery2));
17892 Handle<Object> instance = templ->NewInstance();
17893 CHECK(!instance->HasOwnProperty(v8_str("foo")));
17894 CHECK(instance->HasOwnProperty(v8_str("bar")));
17899 TEST(IndexedInterceptorWithStringProto) {
17900 v8::Isolate* isolate = CcTest::isolate();
17901 v8::HandleScope scope(isolate);
17902 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17903 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
17904 NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
17905 LocalContext context;
17906 context->Global()->Set(v8_str("obj"), templ->NewInstance());
17907 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
17908 // These should be intercepted.
17909 CHECK(CompileRun("42 in obj")->BooleanValue());
17910 CHECK(CompileRun("'42' in obj")->BooleanValue());
17911 // These should fall through to the String prototype.
17912 CHECK(CompileRun("0 in obj")->BooleanValue());
17913 CHECK(CompileRun("'0' in obj")->BooleanValue());
17914 // And these should both fail.
17915 CHECK(!CompileRun("32 in obj")->BooleanValue());
17916 CHECK(!CompileRun("'32' in obj")->BooleanValue());
17920 void CheckCodeGenerationAllowed() {
17921 Handle<Value> result = CompileRun("eval('42')");
17922 CHECK_EQ(42, result->Int32Value());
17923 result = CompileRun("(function(e) { return e('42'); })(eval)");
17924 CHECK_EQ(42, result->Int32Value());
17925 result = CompileRun("var f = new Function('return 42'); f()");
17926 CHECK_EQ(42, result->Int32Value());
17930 void CheckCodeGenerationDisallowed() {
17931 TryCatch try_catch(CcTest::isolate());
17933 Handle<Value> result = CompileRun("eval('42')");
17934 CHECK(result.IsEmpty());
17935 CHECK(try_catch.HasCaught());
17938 result = CompileRun("(function(e) { return e('42'); })(eval)");
17939 CHECK(result.IsEmpty());
17940 CHECK(try_catch.HasCaught());
17943 result = CompileRun("var f = new Function('return 42'); f()");
17944 CHECK(result.IsEmpty());
17945 CHECK(try_catch.HasCaught());
17949 bool CodeGenerationAllowed(Local<Context> context) {
17950 ApiTestFuzzer::Fuzz();
17955 bool CodeGenerationDisallowed(Local<Context> context) {
17956 ApiTestFuzzer::Fuzz();
17961 THREADED_TEST(AllowCodeGenFromStrings) {
17962 LocalContext context;
17963 v8::HandleScope scope(context->GetIsolate());
17965 // eval and the Function constructor allowed by default.
17966 CHECK(context->IsCodeGenerationFromStringsAllowed());
17967 CheckCodeGenerationAllowed();
17969 // Disallow eval and the Function constructor.
17970 context->AllowCodeGenerationFromStrings(false);
17971 CHECK(!context->IsCodeGenerationFromStringsAllowed());
17972 CheckCodeGenerationDisallowed();
17975 context->AllowCodeGenerationFromStrings(true);
17976 CheckCodeGenerationAllowed();
17978 // Disallow but setting a global callback that will allow the calls.
17979 context->AllowCodeGenerationFromStrings(false);
17980 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
17981 CHECK(!context->IsCodeGenerationFromStringsAllowed());
17982 CheckCodeGenerationAllowed();
17984 // Set a callback that disallows the code generation.
17985 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
17986 CHECK(!context->IsCodeGenerationFromStringsAllowed());
17987 CheckCodeGenerationDisallowed();
17991 TEST(SetErrorMessageForCodeGenFromStrings) {
17992 LocalContext context;
17993 v8::HandleScope scope(context->GetIsolate());
17994 TryCatch try_catch(context->GetIsolate());
17996 Handle<String> message = v8_str("Message") ;
17997 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
17998 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
17999 context->AllowCodeGenerationFromStrings(false);
18000 context->SetErrorMessageForCodeGenerationFromStrings(message);
18001 Handle<Value> result = CompileRun("eval('42')");
18002 CHECK(result.IsEmpty());
18003 CHECK(try_catch.HasCaught());
18004 Handle<String> actual_message = try_catch.Message()->Get();
18005 CHECK(expected_message->Equals(actual_message));
18009 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
18013 THREADED_TEST(CallAPIFunctionOnNonObject) {
18014 LocalContext context;
18015 v8::Isolate* isolate = context->GetIsolate();
18016 v8::HandleScope scope(isolate);
18017 Handle<FunctionTemplate> templ =
18018 v8::FunctionTemplate::New(isolate, NonObjectThis);
18019 Handle<Function> function = templ->GetFunction();
18020 context->Global()->Set(v8_str("f"), function);
18021 TryCatch try_catch(isolate);
18022 CompileRun("f.call(2)");
18026 // Regression test for issue 1470.
18027 THREADED_TEST(ReadOnlyIndexedProperties) {
18028 v8::Isolate* isolate = CcTest::isolate();
18029 v8::HandleScope scope(isolate);
18030 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18032 LocalContext context;
18033 Local<v8::Object> obj = templ->NewInstance();
18034 context->Global()->Set(v8_str("obj"), obj);
18035 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18036 obj->Set(v8_str("1"), v8_str("foobar"));
18037 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("1"))));
18038 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
18039 obj->Set(v8_num(2), v8_str("foobar"));
18040 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_num(2))));
18042 // Test non-smi case.
18043 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18044 obj->Set(v8_str("2000000000"), v8_str("foobar"));
18045 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("2000000000"))));
18049 static int CountLiveMapsInMapCache(i::Context* context) {
18050 i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
18051 int length = map_cache->length();
18053 for (int i = 0; i < length; i++) {
18054 i::Object* value = map_cache->get(i);
18055 if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
18061 THREADED_TEST(Regress1516) {
18062 LocalContext context;
18063 v8::HandleScope scope(context->GetIsolate());
18065 // Object with 20 properties is not a common case, so it should be removed
18066 // from the cache after GC.
18067 { v8::HandleScope temp_scope(context->GetIsolate());
18070 "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
18071 "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
18072 "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
18073 "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
18077 int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
18078 CHECK_LE(1, elements);
18080 CcTest::heap()->CollectAllGarbage();
18082 CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
18086 THREADED_TEST(Regress93759) {
18087 v8::Isolate* isolate = CcTest::isolate();
18088 HandleScope scope(isolate);
18090 // Template for object with security check.
18091 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
18092 no_proto_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
18094 // Templates for objects with hidden prototypes and possibly security check.
18095 Local<FunctionTemplate> hidden_proto_template =
18096 v8::FunctionTemplate::New(isolate);
18097 hidden_proto_template->SetHiddenPrototype(true);
18099 Local<FunctionTemplate> protected_hidden_proto_template =
18100 v8::FunctionTemplate::New(isolate);
18101 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
18102 AccessAlwaysBlocked, NULL);
18103 protected_hidden_proto_template->SetHiddenPrototype(true);
18105 // Context for "foreign" objects used in test.
18106 Local<Context> context = v8::Context::New(isolate);
18109 // Plain object, no security check.
18110 Local<Object> simple_object = Object::New(isolate);
18112 // Object with explicit security check.
18113 Local<Object> protected_object = no_proto_template->NewInstance();
18115 // JSGlobalProxy object, always have security check.
18116 Local<Object> proxy_object = context->Global();
18118 // Global object, the prototype of proxy_object. No security checks.
18119 Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
18121 // Hidden prototype without security check.
18122 Local<Object> hidden_prototype =
18123 hidden_proto_template->GetFunction()->NewInstance();
18124 Local<Object> object_with_hidden =
18125 Object::New(isolate);
18126 object_with_hidden->SetPrototype(hidden_prototype);
18128 // Hidden prototype with security check on the hidden prototype.
18129 Local<Object> protected_hidden_prototype =
18130 protected_hidden_proto_template->GetFunction()->NewInstance();
18131 Local<Object> object_with_protected_hidden =
18132 Object::New(isolate);
18133 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
18137 // Template for object for second context. Values to test are put on it as
18139 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
18140 global_template->Set(v8_str("simple"), simple_object);
18141 global_template->Set(v8_str("protected"), protected_object);
18142 global_template->Set(v8_str("global"), global_object);
18143 global_template->Set(v8_str("proxy"), proxy_object);
18144 global_template->Set(v8_str("hidden"), object_with_hidden);
18145 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
18147 LocalContext context2(NULL, global_template);
18149 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
18150 CHECK(result1->Equals(simple_object->GetPrototype()));
18152 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
18153 CHECK(result2.IsEmpty());
18155 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
18156 CHECK(result3->Equals(global_object->GetPrototype()));
18158 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
18159 CHECK(result4.IsEmpty());
18161 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
18162 CHECK(result5->Equals(
18163 object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
18165 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
18166 CHECK(result6.IsEmpty());
18170 static void TestReceiver(Local<Value> expected_result,
18171 Local<Value> expected_receiver,
18172 const char* code) {
18173 Local<Value> result = CompileRun(code);
18174 CHECK(result->IsObject());
18175 CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
18176 CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
18180 THREADED_TEST(ForeignFunctionReceiver) {
18181 v8::Isolate* isolate = CcTest::isolate();
18182 HandleScope scope(isolate);
18184 // Create two contexts with different "id" properties ('i' and 'o').
18185 // Call a function both from its own context and from a the foreign
18186 // context, and see what "this" is bound to (returning both "this"
18187 // and "this.id" for comparison).
18189 Local<Context> foreign_context = v8::Context::New(isolate);
18190 foreign_context->Enter();
18191 Local<Value> foreign_function =
18192 CompileRun("function func() { return { 0: this.id, "
18194 " toString: function() { "
18201 CHECK(foreign_function->IsFunction());
18202 foreign_context->Exit();
18204 LocalContext context;
18206 Local<String> password = v8_str("Password");
18207 // Don't get hit by security checks when accessing foreign_context's
18208 // global receiver (aka. global proxy).
18209 context->SetSecurityToken(password);
18210 foreign_context->SetSecurityToken(password);
18212 Local<String> i = v8_str("i");
18213 Local<String> o = v8_str("o");
18214 Local<String> id = v8_str("id");
18216 CompileRun("function ownfunc() { return { 0: this.id, "
18218 " toString: function() { "
18225 context->Global()->Set(v8_str("func"), foreign_function);
18227 // Sanity check the contexts.
18228 CHECK(i->Equals(foreign_context->Global()->Get(id)));
18229 CHECK(o->Equals(context->Global()->Get(id)));
18231 // Checking local function's receiver.
18232 // Calling function using its call/apply methods.
18233 TestReceiver(o, context->Global(), "ownfunc.call()");
18234 TestReceiver(o, context->Global(), "ownfunc.apply()");
18235 // Making calls through built-in functions.
18236 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
18237 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
18238 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
18239 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
18240 // Calling with environment record as base.
18241 TestReceiver(o, context->Global(), "ownfunc()");
18242 // Calling with no base.
18243 TestReceiver(o, context->Global(), "(1,ownfunc)()");
18245 // Checking foreign function return value.
18246 // Calling function using its call/apply methods.
18247 TestReceiver(i, foreign_context->Global(), "func.call()");
18248 TestReceiver(i, foreign_context->Global(), "func.apply()");
18249 // Calling function using another context's call/apply methods.
18250 TestReceiver(i, foreign_context->Global(),
18251 "Function.prototype.call.call(func)");
18252 TestReceiver(i, foreign_context->Global(),
18253 "Function.prototype.call.apply(func)");
18254 TestReceiver(i, foreign_context->Global(),
18255 "Function.prototype.apply.call(func)");
18256 TestReceiver(i, foreign_context->Global(),
18257 "Function.prototype.apply.apply(func)");
18258 // Making calls through built-in functions.
18259 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
18260 // ToString(func()) is func()[0], i.e., the returned this.id.
18261 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
18262 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
18263 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
18265 // Calling with environment record as base.
18266 TestReceiver(i, foreign_context->Global(), "func()");
18267 // Calling with no base.
18268 TestReceiver(i, foreign_context->Global(), "(1,func)()");
18272 uint8_t callback_fired = 0;
18275 void CallCompletedCallback1() {
18276 v8::base::OS::Print("Firing callback 1.\n");
18277 callback_fired ^= 1; // Toggle first bit.
18281 void CallCompletedCallback2() {
18282 v8::base::OS::Print("Firing callback 2.\n");
18283 callback_fired ^= 2; // Toggle second bit.
18287 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
18288 int32_t level = args[0]->Int32Value();
18291 v8::base::OS::Print("Entering recursion level %d.\n", level);
18293 i::Vector<char> script_vector(script, sizeof(script));
18294 i::SNPrintF(script_vector, "recursion(%d)", level);
18295 CompileRun(script_vector.start());
18296 v8::base::OS::Print("Leaving recursion level %d.\n", level);
18297 CHECK_EQ(0, callback_fired);
18299 v8::base::OS::Print("Recursion ends.\n");
18300 CHECK_EQ(0, callback_fired);
18305 TEST(CallCompletedCallback) {
18307 v8::HandleScope scope(env->GetIsolate());
18308 v8::Handle<v8::FunctionTemplate> recursive_runtime =
18309 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
18310 env->Global()->Set(v8_str("recursion"),
18311 recursive_runtime->GetFunction());
18312 // Adding the same callback a second time has no effect.
18313 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18314 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18315 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
18316 v8::base::OS::Print("--- Script (1) ---\n");
18317 Local<Script> script = v8::Script::Compile(
18318 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
18320 CHECK_EQ(3, callback_fired);
18322 v8::base::OS::Print("\n--- Script (2) ---\n");
18323 callback_fired = 0;
18324 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
18326 CHECK_EQ(2, callback_fired);
18328 v8::base::OS::Print("\n--- Function ---\n");
18329 callback_fired = 0;
18330 Local<Function> recursive_function =
18331 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
18332 v8::Handle<Value> args[] = { v8_num(0) };
18333 recursive_function->Call(env->Global(), 1, args);
18334 CHECK_EQ(2, callback_fired);
18338 void CallCompletedCallbackNoException() {
18339 v8::HandleScope scope(CcTest::isolate());
18340 CompileRun("1+1;");
18344 void CallCompletedCallbackException() {
18345 v8::HandleScope scope(CcTest::isolate());
18346 CompileRun("throw 'second exception';");
18350 TEST(CallCompletedCallbackOneException) {
18352 v8::HandleScope scope(env->GetIsolate());
18353 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
18354 CompileRun("throw 'exception';");
18358 TEST(CallCompletedCallbackTwoExceptions) {
18360 v8::HandleScope scope(env->GetIsolate());
18361 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
18362 CompileRun("throw 'first exception';");
18366 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
18367 v8::HandleScope scope(info.GetIsolate());
18368 CompileRun("ext1Calls++;");
18372 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
18373 v8::HandleScope scope(info.GetIsolate());
18374 CompileRun("ext2Calls++;");
18378 void* g_passed_to_three = NULL;
18381 static void MicrotaskThree(void* data) {
18382 g_passed_to_three = data;
18386 TEST(EnqueueMicrotask) {
18388 v8::HandleScope scope(env->GetIsolate());
18390 "var ext1Calls = 0;"
18391 "var ext2Calls = 0;");
18392 CompileRun("1+1;");
18393 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18394 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18396 env->GetIsolate()->EnqueueMicrotask(
18397 Function::New(env->GetIsolate(), MicrotaskOne));
18398 CompileRun("1+1;");
18399 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18400 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18402 env->GetIsolate()->EnqueueMicrotask(
18403 Function::New(env->GetIsolate(), MicrotaskOne));
18404 env->GetIsolate()->EnqueueMicrotask(
18405 Function::New(env->GetIsolate(), MicrotaskTwo));
18406 CompileRun("1+1;");
18407 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18408 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18410 env->GetIsolate()->EnqueueMicrotask(
18411 Function::New(env->GetIsolate(), MicrotaskTwo));
18412 CompileRun("1+1;");
18413 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18414 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18416 CompileRun("1+1;");
18417 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18418 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18420 g_passed_to_three = NULL;
18421 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
18422 CompileRun("1+1;");
18423 CHECK(!g_passed_to_three);
18424 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18425 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18428 env->GetIsolate()->EnqueueMicrotask(
18429 Function::New(env->GetIsolate(), MicrotaskOne));
18430 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
18431 env->GetIsolate()->EnqueueMicrotask(
18432 Function::New(env->GetIsolate(), MicrotaskTwo));
18433 CompileRun("1+1;");
18434 CHECK_EQ(&dummy, g_passed_to_three);
18435 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
18436 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18437 g_passed_to_three = NULL;
18441 static void MicrotaskExceptionOne(
18442 const v8::FunctionCallbackInfo<Value>& info) {
18443 v8::HandleScope scope(info.GetIsolate());
18444 CompileRun("exception1Calls++;");
18445 info.GetIsolate()->ThrowException(
18446 v8::Exception::Error(v8_str("first")));
18450 static void MicrotaskExceptionTwo(
18451 const v8::FunctionCallbackInfo<Value>& info) {
18452 v8::HandleScope scope(info.GetIsolate());
18453 CompileRun("exception2Calls++;");
18454 info.GetIsolate()->ThrowException(
18455 v8::Exception::Error(v8_str("second")));
18459 TEST(RunMicrotasksIgnoresThrownExceptions) {
18461 v8::Isolate* isolate = env->GetIsolate();
18462 v8::HandleScope scope(isolate);
18464 "var exception1Calls = 0;"
18465 "var exception2Calls = 0;");
18466 isolate->EnqueueMicrotask(
18467 Function::New(isolate, MicrotaskExceptionOne));
18468 isolate->EnqueueMicrotask(
18469 Function::New(isolate, MicrotaskExceptionTwo));
18470 TryCatch try_catch(isolate);
18471 CompileRun("1+1;");
18472 CHECK(!try_catch.HasCaught());
18473 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
18474 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
18478 TEST(SetAutorunMicrotasks) {
18480 v8::HandleScope scope(env->GetIsolate());
18482 "var ext1Calls = 0;"
18483 "var ext2Calls = 0;");
18484 CompileRun("1+1;");
18485 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18486 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18488 env->GetIsolate()->EnqueueMicrotask(
18489 Function::New(env->GetIsolate(), MicrotaskOne));
18490 CompileRun("1+1;");
18491 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18492 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18494 env->GetIsolate()->SetAutorunMicrotasks(false);
18495 env->GetIsolate()->EnqueueMicrotask(
18496 Function::New(env->GetIsolate(), MicrotaskOne));
18497 env->GetIsolate()->EnqueueMicrotask(
18498 Function::New(env->GetIsolate(), MicrotaskTwo));
18499 CompileRun("1+1;");
18500 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18501 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18503 env->GetIsolate()->RunMicrotasks();
18504 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18505 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18507 env->GetIsolate()->EnqueueMicrotask(
18508 Function::New(env->GetIsolate(), MicrotaskTwo));
18509 CompileRun("1+1;");
18510 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18511 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18513 env->GetIsolate()->RunMicrotasks();
18514 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18515 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18517 env->GetIsolate()->SetAutorunMicrotasks(true);
18518 env->GetIsolate()->EnqueueMicrotask(
18519 Function::New(env->GetIsolate(), MicrotaskTwo));
18520 CompileRun("1+1;");
18521 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18522 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18524 env->GetIsolate()->EnqueueMicrotask(
18525 Function::New(env->GetIsolate(), MicrotaskTwo));
18527 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
18528 CompileRun("1+1;");
18529 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18530 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18533 CompileRun("1+1;");
18534 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18535 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
18539 TEST(RunMicrotasksWithoutEnteringContext) {
18540 v8::Isolate* isolate = CcTest::isolate();
18541 HandleScope handle_scope(isolate);
18542 isolate->SetAutorunMicrotasks(false);
18543 Handle<Context> context = Context::New(isolate);
18545 Context::Scope context_scope(context);
18546 CompileRun("var ext1Calls = 0;");
18547 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
18549 isolate->RunMicrotasks();
18551 Context::Scope context_scope(context);
18552 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18554 isolate->SetAutorunMicrotasks(true);
18558 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
18559 v8::DebugEvent event = event_details.GetEvent();
18560 if (event != v8::Break) return;
18561 Handle<Object> exec_state = event_details.GetExecutionState();
18562 Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
18563 CompileRun("function f(id) { new FrameDetails(id, 0); }");
18564 Handle<Function> fun =
18565 Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
18566 fun->Call(CcTest::global(), 1, &break_id);
18570 TEST(Regress385349) {
18571 i::FLAG_allow_natives_syntax = true;
18572 v8::Isolate* isolate = CcTest::isolate();
18573 HandleScope handle_scope(isolate);
18574 isolate->SetAutorunMicrotasks(false);
18575 Handle<Context> context = Context::New(isolate);
18576 v8::Debug::SetDebugEventListener(DebugEventInObserver);
18578 Context::Scope context_scope(context);
18579 CompileRun("var obj = {};"
18580 "Object.observe(obj, function(changes) { debugger; });"
18583 isolate->RunMicrotasks();
18584 isolate->SetAutorunMicrotasks(true);
18585 v8::Debug::SetDebugEventListener(NULL);
18589 #ifdef ENABLE_DISASSEMBLER
18590 static int probes_counter = 0;
18591 static int misses_counter = 0;
18592 static int updates_counter = 0;
18595 static int* LookupCounter(const char* name) {
18596 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
18597 return &probes_counter;
18598 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
18599 return &misses_counter;
18600 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
18601 return &updates_counter;
18607 static const char* kMegamorphicTestProgram =
18608 "function ClassA() { };"
18609 "function ClassB() { };"
18610 "ClassA.prototype.foo = function() { };"
18611 "ClassB.prototype.foo = function() { };"
18612 "function fooify(obj) { obj.foo(); };"
18613 "var a = new ClassA();"
18614 "var b = new ClassB();"
18615 "for (var i = 0; i < 10000; i++) {"
18622 static void StubCacheHelper(bool primary) {
18623 #ifdef ENABLE_DISASSEMBLER
18624 i::FLAG_native_code_counters = true;
18626 i::FLAG_test_primary_stub_cache = true;
18628 i::FLAG_test_secondary_stub_cache = true;
18630 i::FLAG_crankshaft = false;
18632 env->GetIsolate()->SetCounterFunction(LookupCounter);
18633 v8::HandleScope scope(env->GetIsolate());
18634 int initial_probes = probes_counter;
18635 int initial_misses = misses_counter;
18636 int initial_updates = updates_counter;
18637 CompileRun(kMegamorphicTestProgram);
18638 int probes = probes_counter - initial_probes;
18639 int misses = misses_counter - initial_misses;
18640 int updates = updates_counter - initial_updates;
18641 CHECK_LT(updates, 10);
18642 CHECK_LT(misses, 10);
18643 // TODO(verwaest): Update this test to overflow the degree of polymorphism
18644 // before megamorphism. The number of probes will only work once we teach the
18645 // serializer to embed references to counters in the stubs, given that the
18646 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
18647 CHECK_GE(probes, 0);
18652 TEST(SecondaryStubCache) {
18653 StubCacheHelper(true);
18657 TEST(PrimaryStubCache) {
18658 StubCacheHelper(false);
18663 static int cow_arrays_created_runtime = 0;
18666 static int* LookupCounterCOWArrays(const char* name) {
18667 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
18668 return &cow_arrays_created_runtime;
18675 TEST(CheckCOWArraysCreatedRuntimeCounter) {
18677 i::FLAG_native_code_counters = true;
18679 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
18680 v8::HandleScope scope(env->GetIsolate());
18681 int initial_cow_arrays = cow_arrays_created_runtime;
18682 CompileRun("var o = [1, 2, 3];");
18683 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
18684 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
18685 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
18686 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
18687 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
18692 TEST(StaticGetters) {
18693 LocalContext context;
18694 i::Factory* factory = CcTest::i_isolate()->factory();
18695 v8::Isolate* isolate = CcTest::isolate();
18696 v8::HandleScope scope(isolate);
18697 i::Handle<i::Object> undefined_value = factory->undefined_value();
18698 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
18699 i::Handle<i::Object> null_value = factory->null_value();
18700 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
18701 i::Handle<i::Object> true_value = factory->true_value();
18702 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
18703 i::Handle<i::Object> false_value = factory->false_value();
18704 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
18708 UNINITIALIZED_TEST(IsolateEmbedderData) {
18709 CcTest::DisableAutomaticDispose();
18710 v8::Isolate::CreateParams create_params;
18711 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
18712 v8::Isolate* isolate = v8::Isolate::New(create_params);
18714 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
18715 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18716 CHECK(!isolate->GetData(slot));
18717 CHECK(!i_isolate->GetData(slot));
18719 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18720 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
18721 isolate->SetData(slot, data);
18723 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18724 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
18725 CHECK_EQ(data, isolate->GetData(slot));
18726 CHECK_EQ(data, i_isolate->GetData(slot));
18728 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18729 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
18730 isolate->SetData(slot, data);
18732 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
18733 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
18734 CHECK_EQ(data, isolate->GetData(slot));
18735 CHECK_EQ(data, i_isolate->GetData(slot));
18738 isolate->Dispose();
18742 TEST(StringEmpty) {
18743 LocalContext context;
18744 i::Factory* factory = CcTest::i_isolate()->factory();
18745 v8::Isolate* isolate = CcTest::isolate();
18746 v8::HandleScope scope(isolate);
18747 i::Handle<i::Object> empty_string = factory->empty_string();
18748 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
18752 static int instance_checked_getter_count = 0;
18753 static void InstanceCheckedGetter(
18754 Local<String> name,
18755 const v8::PropertyCallbackInfo<v8::Value>& info) {
18756 CHECK(name->Equals(v8_str("foo")));
18757 instance_checked_getter_count++;
18758 info.GetReturnValue().Set(v8_num(11));
18762 static int instance_checked_setter_count = 0;
18763 static void InstanceCheckedSetter(Local<String> name,
18764 Local<Value> value,
18765 const v8::PropertyCallbackInfo<void>& info) {
18766 CHECK(name->Equals(v8_str("foo")));
18767 CHECK(value->Equals(v8_num(23)));
18768 instance_checked_setter_count++;
18772 static void CheckInstanceCheckedResult(int getters, int setters,
18773 bool expects_callbacks,
18774 TryCatch* try_catch) {
18775 if (expects_callbacks) {
18776 CHECK(!try_catch->HasCaught());
18777 CHECK_EQ(getters, instance_checked_getter_count);
18778 CHECK_EQ(setters, instance_checked_setter_count);
18780 CHECK(try_catch->HasCaught());
18781 CHECK_EQ(0, instance_checked_getter_count);
18782 CHECK_EQ(0, instance_checked_setter_count);
18784 try_catch->Reset();
18788 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
18789 instance_checked_getter_count = 0;
18790 instance_checked_setter_count = 0;
18791 TryCatch try_catch(CcTest::isolate());
18793 // Test path through generic runtime code.
18794 CompileRun("obj.foo");
18795 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
18796 CompileRun("obj.foo = 23");
18797 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
18799 // Test path through generated LoadIC and StoredIC.
18800 CompileRun("function test_get(o) { o.foo; }"
18802 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
18803 CompileRun("test_get(obj);");
18804 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
18805 CompileRun("test_get(obj);");
18806 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
18807 CompileRun("function test_set(o) { o.foo = 23; }"
18809 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
18810 CompileRun("test_set(obj);");
18811 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
18812 CompileRun("test_set(obj);");
18813 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
18815 // Test path through optimized code.
18816 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
18818 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
18819 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
18821 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
18823 // Cleanup so that closures start out fresh in next check.
18824 CompileRun("%DeoptimizeFunction(test_get);"
18825 "%ClearFunctionTypeFeedback(test_get);"
18826 "%DeoptimizeFunction(test_set);"
18827 "%ClearFunctionTypeFeedback(test_set);");
18831 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
18832 v8::internal::FLAG_allow_natives_syntax = true;
18833 LocalContext context;
18834 v8::HandleScope scope(context->GetIsolate());
18836 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
18837 Local<ObjectTemplate> inst = templ->InstanceTemplate();
18838 inst->SetAccessor(v8_str("foo"),
18839 InstanceCheckedGetter, InstanceCheckedSetter,
18843 v8::AccessorSignature::New(context->GetIsolate(), templ));
18844 context->Global()->Set(v8_str("f"), templ->GetFunction());
18846 printf("Testing positive ...\n");
18847 CompileRun("var obj = new f();");
18848 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18849 CheckInstanceCheckedAccessors(true);
18851 printf("Testing negative ...\n");
18852 CompileRun("var obj = {};"
18853 "obj.__proto__ = new f();");
18854 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18855 CheckInstanceCheckedAccessors(false);
18859 static void EmptyInterceptorGetter(
18860 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
18863 static void EmptyInterceptorSetter(
18864 Local<String> name, Local<Value> value,
18865 const v8::PropertyCallbackInfo<v8::Value>& info) {}
18868 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
18869 v8::internal::FLAG_allow_natives_syntax = true;
18870 LocalContext context;
18871 v8::HandleScope scope(context->GetIsolate());
18873 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
18874 Local<ObjectTemplate> inst = templ->InstanceTemplate();
18875 templ->InstanceTemplate()->SetNamedPropertyHandler(EmptyInterceptorGetter,
18876 EmptyInterceptorSetter);
18877 inst->SetAccessor(v8_str("foo"),
18878 InstanceCheckedGetter, InstanceCheckedSetter,
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);
18898 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
18899 v8::internal::FLAG_allow_natives_syntax = true;
18900 LocalContext context;
18901 v8::HandleScope scope(context->GetIsolate());
18903 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
18904 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
18905 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
18906 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
18908 v8::AccessorSignature::New(context->GetIsolate(), templ));
18909 context->Global()->Set(v8_str("f"), templ->GetFunction());
18911 printf("Testing positive ...\n");
18912 CompileRun("var obj = new f();");
18913 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18914 CheckInstanceCheckedAccessors(true);
18916 printf("Testing negative ...\n");
18917 CompileRun("var obj = {};"
18918 "obj.__proto__ = new f();");
18919 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18920 CheckInstanceCheckedAccessors(false);
18922 printf("Testing positive with modified prototype chain ...\n");
18923 CompileRun("var obj = new f();"
18925 "pro.__proto__ = obj.__proto__;"
18926 "obj.__proto__ = pro;");
18927 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
18928 CheckInstanceCheckedAccessors(true);
18932 TEST(TryFinallyMessage) {
18933 LocalContext context;
18934 v8::HandleScope scope(context->GetIsolate());
18936 // Test that the original error message is not lost if there is a
18937 // recursive call into Javascript is done in the finally block, e.g. to
18938 // initialize an IC. (crbug.com/129171)
18939 TryCatch try_catch(context->GetIsolate());
18940 const char* trigger_ic =
18942 " throw new Error('test'); \n"
18945 " x++; \n" // Trigger an IC initialization here.
18947 CompileRun(trigger_ic);
18948 CHECK(try_catch.HasCaught());
18949 Local<Message> message = try_catch.Message();
18950 CHECK(!message.IsEmpty());
18951 CHECK_EQ(2, message->GetLineNumber());
18955 // Test that the original exception message is indeed overwritten if
18956 // a new error is thrown in the finally block.
18957 TryCatch try_catch(context->GetIsolate());
18958 const char* throw_again =
18960 " throw new Error('test'); \n"
18964 " throw new Error('again'); \n" // This is the new uncaught error.
18966 CompileRun(throw_again);
18967 CHECK(try_catch.HasCaught());
18968 Local<Message> message = try_catch.Message();
18969 CHECK(!message.IsEmpty());
18970 CHECK_EQ(6, message->GetLineNumber());
18975 static void Helper137002(bool do_store,
18977 bool remove_accessor,
18978 bool interceptor) {
18979 LocalContext context;
18980 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
18982 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
18983 FooSetInterceptor));
18985 templ->SetAccessor(v8_str("foo"),
18986 GetterWhichReturns42,
18987 SetterWhichSetsYOnThisTo23);
18989 context->Global()->Set(v8_str("obj"), templ->NewInstance());
18991 // Turn monomorphic on slow object with native accessor, then turn
18992 // polymorphic, finally optimize to create negative lookup and fail.
18993 CompileRun(do_store ?
18994 "function f(x) { x.foo = void 0; }" :
18995 "function f(x) { return x.foo; }");
18996 CompileRun("obj.y = void 0;");
18997 if (!interceptor) {
18998 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
19000 CompileRun("obj.__proto__ = null;"
19001 "f(obj); f(obj); f(obj);");
19003 CompileRun("f({});");
19005 CompileRun("obj.y = void 0;"
19006 "%OptimizeFunctionOnNextCall(f);");
19007 if (remove_accessor) {
19008 CompileRun("delete obj.foo;");
19010 CompileRun("var result = f(obj);");
19012 CompileRun("result = obj.y;");
19014 if (remove_accessor && !interceptor) {
19015 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
19017 CHECK_EQ(do_store ? 23 : 42,
19018 context->Global()->Get(v8_str("result"))->Int32Value());
19023 THREADED_TEST(Regress137002a) {
19024 i::FLAG_allow_natives_syntax = true;
19025 i::FLAG_compilation_cache = false;
19026 v8::HandleScope scope(CcTest::isolate());
19027 for (int i = 0; i < 16; i++) {
19028 Helper137002(i & 8, i & 4, i & 2, i & 1);
19033 THREADED_TEST(Regress137002b) {
19034 i::FLAG_allow_natives_syntax = true;
19035 LocalContext context;
19036 v8::Isolate* isolate = context->GetIsolate();
19037 v8::HandleScope scope(isolate);
19038 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19039 templ->SetAccessor(v8_str("foo"),
19040 GetterWhichReturns42,
19041 SetterWhichSetsYOnThisTo23);
19042 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19044 // Turn monomorphic on slow object with native accessor, then just
19045 // delete the property and fail.
19046 CompileRun("function load(x) { return x.foo; }"
19047 "function store(x) { x.foo = void 0; }"
19048 "function keyed_load(x, key) { return x[key]; }"
19049 // Second version of function has a different source (add void 0)
19050 // so that it does not share code with the first version. This
19051 // ensures that the ICs are monomorphic.
19052 "function load2(x) { void 0; return x.foo; }"
19053 "function store2(x) { void 0; x.foo = void 0; }"
19054 "function keyed_load2(x, key) { void 0; return x[key]; }"
19057 "obj.__proto__ = null;"
19059 "subobj.y = void 0;"
19060 "subobj.__proto__ = obj;"
19061 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19063 // Make the ICs monomorphic.
19064 "load(obj); load(obj);"
19065 "load2(subobj); load2(subobj);"
19066 "store(obj); store(obj);"
19067 "store2(subobj); store2(subobj);"
19068 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
19069 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
19071 // Actually test the shiny new ICs and better not crash. This
19072 // serves as a regression test for issue 142088 as well.
19077 "keyed_load(obj, 'foo');"
19078 "keyed_load2(subobj, 'foo');"
19080 // Delete the accessor. It better not be called any more now.
19083 "subobj.y = void 0;"
19085 "var load_result = load(obj);"
19086 "var load_result2 = load2(subobj);"
19087 "var keyed_load_result = keyed_load(obj, 'foo');"
19088 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
19091 "var y_from_obj = obj.y;"
19092 "var y_from_subobj = subobj.y;");
19093 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
19094 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
19095 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
19096 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
19097 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
19098 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
19102 THREADED_TEST(Regress142088) {
19103 i::FLAG_allow_natives_syntax = true;
19104 LocalContext context;
19105 v8::Isolate* isolate = context->GetIsolate();
19106 v8::HandleScope scope(isolate);
19107 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19108 templ->SetAccessor(v8_str("foo"),
19109 GetterWhichReturns42,
19110 SetterWhichSetsYOnThisTo23);
19111 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19113 CompileRun("function load(x) { return x.foo; }"
19114 "var o = Object.create(obj);"
19115 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19116 "load(o); load(o); load(o); load(o);");
19120 THREADED_TEST(Regress137496) {
19121 i::FLAG_expose_gc = true;
19122 LocalContext context;
19123 v8::HandleScope scope(context->GetIsolate());
19125 // Compile a try-finally clause where the finally block causes a GC
19126 // while there still is a message pending for external reporting.
19127 TryCatch try_catch(context->GetIsolate());
19128 try_catch.SetVerbose(true);
19129 CompileRun("try { throw new Error(); } finally { gc(); }");
19130 CHECK(try_catch.HasCaught());
19134 THREADED_TEST(Regress157124) {
19135 LocalContext context;
19136 v8::Isolate* isolate = context->GetIsolate();
19137 v8::HandleScope scope(isolate);
19138 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19139 Local<Object> obj = templ->NewInstance();
19140 obj->GetIdentityHash();
19141 obj->DeleteHiddenValue(v8_str("Bug"));
19145 THREADED_TEST(Regress2535) {
19146 LocalContext context;
19147 v8::HandleScope scope(context->GetIsolate());
19148 Local<Value> set_value = CompileRun("new Set();");
19149 Local<Object> set_object(Local<Object>::Cast(set_value));
19150 CHECK_EQ(0, set_object->InternalFieldCount());
19151 Local<Value> map_value = CompileRun("new Map();");
19152 Local<Object> map_object(Local<Object>::Cast(map_value));
19153 CHECK_EQ(0, map_object->InternalFieldCount());
19157 THREADED_TEST(Regress2746) {
19158 LocalContext context;
19159 v8::Isolate* isolate = context->GetIsolate();
19160 v8::HandleScope scope(isolate);
19161 Local<Object> obj = Object::New(isolate);
19162 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
19163 obj->SetHiddenValue(key, v8::Undefined(isolate));
19164 Local<Value> value = obj->GetHiddenValue(key);
19165 CHECK(!value.IsEmpty());
19166 CHECK(value->IsUndefined());
19170 THREADED_TEST(Regress260106) {
19171 LocalContext context;
19172 v8::Isolate* isolate = context->GetIsolate();
19173 v8::HandleScope scope(isolate);
19174 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
19176 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
19177 Local<Function> function = templ->GetFunction();
19178 CHECK(!function.IsEmpty());
19179 CHECK(function->IsFunction());
19183 THREADED_TEST(JSONParseObject) {
19184 LocalContext context;
19185 HandleScope scope(context->GetIsolate());
19186 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
19187 Handle<Object> global = context->Global();
19188 global->Set(v8_str("obj"), obj);
19189 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
19193 THREADED_TEST(JSONParseNumber) {
19194 LocalContext context;
19195 HandleScope scope(context->GetIsolate());
19196 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
19197 Handle<Object> global = context->Global();
19198 global->Set(v8_str("obj"), obj);
19199 ExpectString("JSON.stringify(obj)", "42");
19203 #if V8_OS_POSIX && !V8_OS_NACL
19204 class ThreadInterruptTest {
19206 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
19207 ~ThreadInterruptTest() {}
19210 InterruptThread i_thread(this);
19214 CHECK_EQ(kExpectedValue, sem_value_);
19218 static const int kExpectedValue = 1;
19220 class InterruptThread : public v8::base::Thread {
19222 explicit InterruptThread(ThreadInterruptTest* test)
19223 : Thread(Options("InterruptThread")), test_(test) {}
19225 virtual void Run() {
19226 struct sigaction action;
19228 // Ensure that we'll enter waiting condition
19229 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
19231 // Setup signal handler
19232 memset(&action, 0, sizeof(action));
19233 action.sa_handler = SignalHandler;
19234 sigaction(SIGCHLD, &action, NULL);
19237 kill(getpid(), SIGCHLD);
19239 // Ensure that if wait has returned because of error
19240 v8::base::OS::Sleep(v8::base::TimeDelta::FromMilliseconds(100));
19242 // Set value and signal semaphore
19243 test_->sem_value_ = 1;
19244 test_->sem_.Signal();
19247 static void SignalHandler(int signal) {
19251 ThreadInterruptTest* test_;
19254 v8::base::Semaphore sem_;
19255 volatile int sem_value_;
19259 THREADED_TEST(SemaphoreInterruption) {
19260 ThreadInterruptTest().RunTest();
19264 #endif // V8_OS_POSIX
19267 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19272 TEST(JSONStringifyAccessCheck) {
19273 v8::V8::Initialize();
19274 v8::Isolate* isolate = CcTest::isolate();
19275 v8::HandleScope scope(isolate);
19277 // Create an ObjectTemplate for global objects and install access
19278 // check callbacks that will block access.
19279 v8::Handle<v8::ObjectTemplate> global_template =
19280 v8::ObjectTemplate::New(isolate);
19281 global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
19283 // Create a context and set an x property on it's global object.
19284 LocalContext context0(NULL, global_template);
19285 v8::Handle<v8::Object> global0 = context0->Global();
19286 global0->Set(v8_str("x"), v8_num(42));
19287 ExpectString("JSON.stringify(this)", "{\"x\":42}");
19289 for (int i = 0; i < 2; i++) {
19291 // Install a toJSON function on the second run.
19292 v8::Handle<v8::FunctionTemplate> toJSON =
19293 v8::FunctionTemplate::New(isolate, UnreachableCallback);
19295 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
19297 // Create a context with a different security token so that the
19298 // failed access check callback will be called on each access.
19299 LocalContext context1(NULL, global_template);
19300 context1->Global()->Set(v8_str("other"), global0);
19302 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
19303 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
19304 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
19309 bool access_check_fail_thrown = false;
19310 bool catch_callback_called = false;
19313 // Failed access check callback that performs a GC on each invocation.
19314 void FailedAccessCheckThrows(Local<v8::Object> target,
19315 v8::AccessType type,
19316 Local<v8::Value> data) {
19317 access_check_fail_thrown = true;
19318 i::PrintF("Access check failed. Error thrown.\n");
19319 CcTest::isolate()->ThrowException(
19320 v8::Exception::Error(v8_str("cross context")));
19324 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19325 for (int i = 0; i < args.Length(); i++) {
19326 i::PrintF("%s\n", *String::Utf8Value(args[i]));
19328 catch_callback_called = true;
19332 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19333 args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
19334 args[1]->ToString(args.GetIsolate()));
19338 void CheckCorrectThrow(const char* script) {
19339 // Test that the script, when wrapped into a try-catch, triggers the catch
19340 // clause due to failed access check throwing an exception.
19341 // The subsequent try-catch should run without any exception.
19342 access_check_fail_thrown = false;
19343 catch_callback_called = false;
19344 i::ScopedVector<char> source(1024);
19345 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
19346 CompileRun(source.start());
19347 CHECK(access_check_fail_thrown);
19348 CHECK(catch_callback_called);
19350 access_check_fail_thrown = false;
19351 catch_callback_called = false;
19352 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
19353 CHECK(!access_check_fail_thrown);
19354 CHECK(!catch_callback_called);
19358 TEST(AccessCheckThrows) {
19359 i::FLAG_allow_natives_syntax = true;
19360 i::FLAG_turbo_try_catch = true;
19361 v8::V8::Initialize();
19362 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
19363 v8::Isolate* isolate = CcTest::isolate();
19364 v8::HandleScope scope(isolate);
19366 // Create an ObjectTemplate for global objects and install access
19367 // check callbacks that will block access.
19368 v8::Handle<v8::ObjectTemplate> global_template =
19369 v8::ObjectTemplate::New(isolate);
19370 global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
19372 // Create a context and set an x property on it's global object.
19373 LocalContext context0(NULL, global_template);
19374 v8::Handle<v8::Object> global0 = context0->Global();
19376 // Create a context with a different security token so that the
19377 // failed access check callback will be called on each access.
19378 LocalContext context1(NULL, global_template);
19379 context1->Global()->Set(v8_str("other"), global0);
19381 v8::Handle<v8::FunctionTemplate> catcher_fun =
19382 v8::FunctionTemplate::New(isolate, CatcherCallback);
19383 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
19385 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
19386 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
19387 context1->Global()->Set(v8_str("has_own_property"),
19388 has_own_property_fun->GetFunction());
19391 v8::TryCatch try_catch(isolate);
19392 access_check_fail_thrown = false;
19393 CompileRun("other.x;");
19394 CHECK(access_check_fail_thrown);
19395 CHECK(try_catch.HasCaught());
19398 CheckCorrectThrow("other.x");
19399 CheckCorrectThrow("other[1]");
19400 CheckCorrectThrow("JSON.stringify(other)");
19401 CheckCorrectThrow("has_own_property(other, 'x')");
19402 CheckCorrectThrow("%GetProperty(other, 'x')");
19403 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
19404 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
19405 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
19406 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
19407 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
19408 CheckCorrectThrow("%HasProperty(other, 'x')");
19409 CheckCorrectThrow("%HasElement(other, 1)");
19410 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
19411 CheckCorrectThrow("%GetPropertyNames(other)");
19412 // PROPERTY_ATTRIBUTES_NONE = 0
19413 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
19414 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
19415 "other, 'x', null, null, 1)");
19417 // Reset the failed access check callback so it does not influence
19418 // the other tests.
19419 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19423 class RequestInterruptTestBase {
19425 RequestInterruptTestBase()
19427 isolate_(env_->GetIsolate()),
19430 should_continue_(true) {
19433 virtual ~RequestInterruptTestBase() { }
19435 virtual void StartInterruptThread() = 0;
19437 virtual void TestBody() = 0;
19440 StartInterruptThread();
19442 v8::HandleScope handle_scope(isolate_);
19446 // Verify we arrived here because interruptor was called
19447 // not due to a bug causing us to exit the loop too early.
19448 CHECK(!should_continue());
19451 void WakeUpInterruptor() {
19455 bool should_continue() const { return should_continue_; }
19457 bool ShouldContinue() {
19459 if (--warmup_ == 0) {
19460 WakeUpInterruptor();
19464 return should_continue_;
19467 static void ShouldContinueCallback(
19468 const v8::FunctionCallbackInfo<Value>& info) {
19469 RequestInterruptTestBase* test =
19470 reinterpret_cast<RequestInterruptTestBase*>(
19471 info.Data().As<v8::External>()->Value());
19472 info.GetReturnValue().Set(test->ShouldContinue());
19476 v8::Isolate* isolate_;
19477 v8::base::Semaphore sem_;
19479 bool should_continue_;
19483 class RequestInterruptTestBaseWithSimpleInterrupt
19484 : public RequestInterruptTestBase {
19486 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
19488 virtual void StartInterruptThread() {
19493 class InterruptThread : public v8::base::Thread {
19495 explicit InterruptThread(RequestInterruptTestBase* test)
19496 : Thread(Options("RequestInterruptTest")), test_(test) {}
19498 virtual void Run() {
19499 test_->sem_.Wait();
19500 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
19503 static void OnInterrupt(v8::Isolate* isolate, void* data) {
19504 reinterpret_cast<RequestInterruptTestBase*>(data)->
19505 should_continue_ = false;
19509 RequestInterruptTestBase* test_;
19512 InterruptThread i_thread;
19516 class RequestInterruptTestWithFunctionCall
19517 : public RequestInterruptTestBaseWithSimpleInterrupt {
19519 virtual void TestBody() {
19520 Local<Function> func = Function::New(
19521 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
19522 env_->Global()->Set(v8_str("ShouldContinue"), func);
19524 CompileRun("while (ShouldContinue()) { }");
19529 class RequestInterruptTestWithMethodCall
19530 : public RequestInterruptTestBaseWithSimpleInterrupt {
19532 virtual void TestBody() {
19533 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19534 v8::Local<v8::Template> proto = t->PrototypeTemplate();
19535 proto->Set(v8_str("shouldContinue"), Function::New(
19536 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
19537 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19539 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
19544 class RequestInterruptTestWithAccessor
19545 : public RequestInterruptTestBaseWithSimpleInterrupt {
19547 virtual void TestBody() {
19548 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19549 v8::Local<v8::Template> proto = t->PrototypeTemplate();
19550 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
19551 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
19552 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19554 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
19559 class RequestInterruptTestWithNativeAccessor
19560 : public RequestInterruptTestBaseWithSimpleInterrupt {
19562 virtual void TestBody() {
19563 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19564 t->InstanceTemplate()->SetNativeDataProperty(
19565 v8_str("shouldContinue"),
19566 &ShouldContinueNativeGetter,
19568 v8::External::New(isolate_, this));
19569 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19571 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
19575 static void ShouldContinueNativeGetter(
19576 Local<String> property,
19577 const v8::PropertyCallbackInfo<v8::Value>& info) {
19578 RequestInterruptTestBase* test =
19579 reinterpret_cast<RequestInterruptTestBase*>(
19580 info.Data().As<v8::External>()->Value());
19581 info.GetReturnValue().Set(test->ShouldContinue());
19586 class RequestInterruptTestWithMethodCallAndInterceptor
19587 : public RequestInterruptTestBaseWithSimpleInterrupt {
19589 virtual void TestBody() {
19590 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
19591 v8::Local<v8::Template> proto = t->PrototypeTemplate();
19592 proto->Set(v8_str("shouldContinue"), Function::New(
19593 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
19594 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
19595 instance_template->SetHandler(
19596 v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
19598 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
19600 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
19604 static void EmptyInterceptor(
19605 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
19609 class RequestInterruptTestWithMathAbs
19610 : public RequestInterruptTestBaseWithSimpleInterrupt {
19612 virtual void TestBody() {
19613 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
19615 WakeUpInterruptorCallback,
19616 v8::External::New(isolate_, this)));
19618 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
19620 ShouldContinueCallback,
19621 v8::External::New(isolate_, this)));
19623 i::FLAG_allow_natives_syntax = true;
19624 CompileRun("function loopish(o) {"
19626 " while (o.abs(1) > 0) {"
19627 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
19629 " if (--pre === 0) WakeUpInterruptor(o === Math);"
19634 "var obj = {abs: function () { return i-- }, x: null};"
19637 "%OptimizeFunctionOnNextCall(loopish);"
19640 i::FLAG_allow_natives_syntax = false;
19644 static void WakeUpInterruptorCallback(
19645 const v8::FunctionCallbackInfo<Value>& info) {
19646 if (!info[0]->BooleanValue()) return;
19648 RequestInterruptTestBase* test =
19649 reinterpret_cast<RequestInterruptTestBase*>(
19650 info.Data().As<v8::External>()->Value());
19651 test->WakeUpInterruptor();
19654 static void ShouldContinueCallback(
19655 const v8::FunctionCallbackInfo<Value>& info) {
19656 RequestInterruptTestBase* test =
19657 reinterpret_cast<RequestInterruptTestBase*>(
19658 info.Data().As<v8::External>()->Value());
19659 info.GetReturnValue().Set(test->should_continue());
19664 TEST(RequestInterruptTestWithFunctionCall) {
19665 RequestInterruptTestWithFunctionCall().RunTest();
19669 TEST(RequestInterruptTestWithMethodCall) {
19670 RequestInterruptTestWithMethodCall().RunTest();
19674 TEST(RequestInterruptTestWithAccessor) {
19675 RequestInterruptTestWithAccessor().RunTest();
19679 TEST(RequestInterruptTestWithNativeAccessor) {
19680 RequestInterruptTestWithNativeAccessor().RunTest();
19684 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
19685 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
19689 TEST(RequestInterruptTestWithMathAbs) {
19690 RequestInterruptTestWithMathAbs().RunTest();
19694 class RequestMultipleInterrupts : public RequestInterruptTestBase {
19696 RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
19698 virtual void StartInterruptThread() {
19702 virtual void TestBody() {
19703 Local<Function> func = Function::New(
19704 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
19705 env_->Global()->Set(v8_str("ShouldContinue"), func);
19707 CompileRun("while (ShouldContinue()) { }");
19711 class InterruptThread : public v8::base::Thread {
19713 enum { NUM_INTERRUPTS = 10 };
19714 explicit InterruptThread(RequestMultipleInterrupts* test)
19715 : Thread(Options("RequestInterruptTest")), test_(test) {}
19717 virtual void Run() {
19718 test_->sem_.Wait();
19719 for (int i = 0; i < NUM_INTERRUPTS; i++) {
19720 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
19724 static void OnInterrupt(v8::Isolate* isolate, void* data) {
19725 RequestMultipleInterrupts* test =
19726 reinterpret_cast<RequestMultipleInterrupts*>(data);
19727 test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
19731 RequestMultipleInterrupts* test_;
19734 InterruptThread i_thread;
19739 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
19742 static bool interrupt_was_called = false;
19745 void SmallScriptsInterruptCallback(v8::Isolate* isolate, void* data) {
19746 interrupt_was_called = true;
19750 TEST(RequestInterruptSmallScripts) {
19752 v8::Isolate* isolate = CcTest::isolate();
19753 v8::HandleScope scope(isolate);
19755 interrupt_was_called = false;
19756 isolate->RequestInterrupt(&SmallScriptsInterruptCallback, NULL);
19757 CompileRun("(function(x){return x;})(1);");
19758 CHECK(interrupt_was_called);
19762 static Local<Value> function_new_expected_env;
19763 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
19764 CHECK(function_new_expected_env->Equals(info.Data()));
19765 info.GetReturnValue().Set(17);
19769 THREADED_TEST(FunctionNew) {
19771 v8::Isolate* isolate = env->GetIsolate();
19772 v8::HandleScope scope(isolate);
19773 Local<Object> data = v8::Object::New(isolate);
19774 function_new_expected_env = data;
19775 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
19776 env->Global()->Set(v8_str("func"), func);
19777 Local<Value> result = CompileRun("func();");
19778 CHECK(v8::Integer::New(isolate, 17)->Equals(result));
19779 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
19780 // Verify function not cached
19781 auto serial_number = handle(i::Smi::cast(v8::Utils::OpenHandle(*func)
19783 ->get_api_func_data()
19784 ->serial_number()),
19786 auto cache = i_isolate->function_cache();
19787 CHECK(cache->Lookup(serial_number)->IsTheHole());
19788 // Verify that each Function::New creates a new function instance
19789 Local<Object> data2 = v8::Object::New(isolate);
19790 function_new_expected_env = data2;
19791 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
19792 CHECK(!func2->IsNull());
19793 CHECK(!func->Equals(func2));
19794 env->Global()->Set(v8_str("func2"), func2);
19795 Local<Value> result2 = CompileRun("func2();");
19796 CHECK(v8::Integer::New(isolate, 17)->Equals(result2));
19800 TEST(EscapeableHandleScope) {
19801 HandleScope outer_scope(CcTest::isolate());
19802 LocalContext context;
19803 const int runs = 10;
19804 Local<String> values[runs];
19805 for (int i = 0; i < runs; i++) {
19806 v8::EscapableHandleScope inner_scope(CcTest::isolate());
19807 Local<String> value;
19808 if (i != 0) value = v8_str("escape value");
19809 values[i] = inner_scope.Escape(value);
19811 for (int i = 0; i < runs; i++) {
19812 Local<String> expected;
19814 CHECK(v8_str("escape value")->Equals(values[i]));
19816 CHECK(values[i].IsEmpty());
19822 static void SetterWhichExpectsThisAndHolderToDiffer(
19823 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
19824 CHECK(info.Holder() != info.This());
19828 TEST(Regress239669) {
19829 LocalContext context;
19830 v8::Isolate* isolate = context->GetIsolate();
19831 v8::HandleScope scope(isolate);
19832 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19833 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
19834 context->Global()->Set(v8_str("P"), templ->NewInstance());
19839 "C1.prototype = P;"
19840 "for (var i = 0; i < 4; i++ ) {"
19846 class ApiCallOptimizationChecker {
19848 static Local<Object> data;
19849 static Local<Object> receiver;
19850 static Local<Object> holder;
19851 static Local<Object> callee;
19854 static void OptimizationCallback(
19855 const v8::FunctionCallbackInfo<v8::Value>& info) {
19856 CHECK(callee == info.Callee());
19857 CHECK(data == info.Data());
19858 CHECK(receiver == info.This());
19859 if (info.Length() == 1) {
19860 CHECK(v8_num(1)->Equals(info[0]));
19862 CHECK(holder == info.Holder());
19864 info.GetReturnValue().Set(v8_str("returned"));
19868 enum SignatureType {
19870 kSignatureOnReceiver,
19871 kSignatureOnPrototype
19875 SignatureType signature_types[] =
19876 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
19877 for (unsigned i = 0; i < arraysize(signature_types); i++) {
19878 SignatureType signature_type = signature_types[i];
19879 for (int j = 0; j < 2; j++) {
19880 bool global = j == 0;
19881 int key = signature_type +
19882 arraysize(signature_types) * (global ? 1 : 0);
19883 Run(signature_type, global, key);
19888 void Run(SignatureType signature_type, bool global, int key) {
19889 v8::Isolate* isolate = CcTest::isolate();
19890 v8::HandleScope scope(isolate);
19891 // Build a template for signature checks.
19892 Local<v8::ObjectTemplate> signature_template;
19893 Local<v8::Signature> signature;
19895 Local<v8::FunctionTemplate> parent_template =
19896 FunctionTemplate::New(isolate);
19897 parent_template->SetHiddenPrototype(true);
19898 Local<v8::FunctionTemplate> function_template
19899 = FunctionTemplate::New(isolate);
19900 function_template->Inherit(parent_template);
19901 switch (signature_type) {
19904 case kSignatureOnReceiver:
19905 signature = v8::Signature::New(isolate, function_template);
19907 case kSignatureOnPrototype:
19908 signature = v8::Signature::New(isolate, parent_template);
19911 signature_template = function_template->InstanceTemplate();
19913 // Global object must pass checks.
19914 Local<v8::Context> context =
19915 v8::Context::New(isolate, NULL, signature_template);
19916 v8::Context::Scope context_scope(context);
19917 // Install regular object that can pass signature checks.
19918 Local<Object> function_receiver = signature_template->NewInstance();
19919 context->Global()->Set(v8_str("function_receiver"), function_receiver);
19920 // Get the holder objects.
19921 Local<Object> inner_global =
19922 Local<Object>::Cast(context->Global()->GetPrototype());
19923 // Install functions on hidden prototype object if there is one.
19924 data = Object::New(isolate);
19925 Local<FunctionTemplate> function_template = FunctionTemplate::New(
19926 isolate, OptimizationCallback, data, signature);
19927 Local<Function> function = function_template->GetFunction();
19928 Local<Object> global_holder = inner_global;
19929 Local<Object> function_holder = function_receiver;
19930 if (signature_type == kSignatureOnPrototype) {
19931 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
19932 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
19934 global_holder->Set(v8_str("g_f"), function);
19935 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
19936 function_holder->Set(v8_str("f"), function);
19937 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
19938 // Initialize expected values.
19942 receiver = context->Global();
19943 holder = inner_global;
19945 holder = function_receiver;
19946 // If not using a signature, add something else to the prototype chain
19947 // to test the case that holder != receiver
19948 if (signature_type == kNoSignature) {
19949 receiver = Local<Object>::Cast(CompileRun(
19950 "var receiver_subclass = {};\n"
19951 "receiver_subclass.__proto__ = function_receiver;\n"
19952 "receiver_subclass"));
19954 receiver = Local<Object>::Cast(CompileRun(
19955 "var receiver_subclass = function_receiver;\n"
19956 "receiver_subclass"));
19959 // With no signature, the holder is not set.
19960 if (signature_type == kNoSignature) holder = receiver;
19961 // build wrap_function
19962 i::ScopedVector<char> wrap_function(200);
19966 "function wrap_f_%d() { var f = g_f; return f(); }\n"
19967 "function wrap_get_%d() { return this.g_acc; }\n"
19968 "function wrap_set_%d() { return this.g_acc = 1; }\n",
19973 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
19974 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
19975 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
19978 // build source string
19979 i::ScopedVector<char> source(1000);
19982 "%s\n" // wrap functions
19983 "function wrap_f() { return wrap_f_%d(); }\n"
19984 "function wrap_get() { return wrap_get_%d(); }\n"
19985 "function wrap_set() { return wrap_set_%d(); }\n"
19986 "check = function(returned) {\n"
19987 " if (returned !== 'returned') { throw returned; }\n"
19990 "check(wrap_f());\n"
19991 "check(wrap_f());\n"
19992 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
19993 "check(wrap_f());\n"
19995 "check(wrap_get());\n"
19996 "check(wrap_get());\n"
19997 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
19998 "check(wrap_get());\n"
20000 "check = function(returned) {\n"
20001 " if (returned !== 1) { throw returned; }\n"
20003 "check(wrap_set());\n"
20004 "check(wrap_set());\n"
20005 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
20006 "check(wrap_set());\n",
20007 wrap_function.start(), key, key, key, key, key, key);
20008 v8::TryCatch try_catch(isolate);
20009 CompileRun(source.start());
20010 DCHECK(!try_catch.HasCaught());
20011 CHECK_EQ(9, count);
20016 Local<Object> ApiCallOptimizationChecker::data;
20017 Local<Object> ApiCallOptimizationChecker::receiver;
20018 Local<Object> ApiCallOptimizationChecker::holder;
20019 Local<Object> ApiCallOptimizationChecker::callee;
20020 int ApiCallOptimizationChecker::count = 0;
20023 TEST(FunctionCallOptimization) {
20024 i::FLAG_allow_natives_syntax = true;
20025 ApiCallOptimizationChecker checker;
20030 TEST(FunctionCallOptimizationMultipleArgs) {
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, Returns42);
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 static void ReturnsSymbolCallback(
20051 const v8::FunctionCallbackInfo<v8::Value>& info) {
20052 info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
20056 TEST(ApiCallbackCanReturnSymbols) {
20057 i::FLAG_allow_natives_syntax = true;
20058 LocalContext context;
20059 v8::Isolate* isolate = context->GetIsolate();
20060 v8::HandleScope scope(isolate);
20061 Handle<Object> global = context->Global();
20062 Local<v8::Function> function = Function::New(isolate, ReturnsSymbolCallback);
20063 global->Set(v8_str("x"), function);
20065 "function x_wrap() {\n"
20066 " for (var i = 0; i < 5; i++) {\n"
20071 "%OptimizeFunctionOnNextCall(x_wrap);"
20076 TEST(EmptyApiCallback) {
20077 LocalContext context;
20078 auto isolate = context->GetIsolate();
20079 v8::HandleScope scope(isolate);
20080 auto global = context->Global();
20081 auto function = FunctionTemplate::New(isolate)->GetFunction();
20082 global->Set(v8_str("x"), function);
20084 auto result = CompileRun("x()");
20085 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20087 result = CompileRun("x(1,2,3)");
20088 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20090 result = CompileRun("7 + x.call(3) + 11");
20091 CHECK(result->IsInt32());
20092 CHECK_EQ(21, result->Int32Value());
20094 result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
20095 CHECK(result->IsInt32());
20096 CHECK_EQ(21, result->Int32Value());
20098 result = CompileRun("var y = []; x.call(y)");
20099 CHECK(result->IsArray());
20101 result = CompileRun("x.call(y, 1, 2, 3, 4)");
20102 CHECK(result->IsArray());
20106 TEST(SimpleSignatureCheck) {
20107 LocalContext context;
20108 auto isolate = context->GetIsolate();
20109 v8::HandleScope scope(isolate);
20110 auto global = context->Global();
20111 auto sig_obj = FunctionTemplate::New(isolate);
20112 auto sig = v8::Signature::New(isolate, sig_obj);
20113 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20114 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20115 global->Set(v8_str("x"), x->GetFunction());
20116 CompileRun("var s = new sig_obj();");
20118 TryCatch try_catch(isolate);
20120 CHECK(try_catch.HasCaught());
20123 TryCatch try_catch(isolate);
20124 CompileRun("x.call(1)");
20125 CHECK(try_catch.HasCaught());
20128 TryCatch try_catch(isolate);
20129 auto result = CompileRun("s.x = x; s.x()");
20130 CHECK(!try_catch.HasCaught());
20131 CHECK_EQ(42, result->Int32Value());
20134 TryCatch try_catch(isolate);
20135 auto result = CompileRun("x.call(s)");
20136 CHECK(!try_catch.HasCaught());
20137 CHECK_EQ(42, result->Int32Value());
20142 TEST(ChainSignatureCheck) {
20143 LocalContext context;
20144 auto isolate = context->GetIsolate();
20145 v8::HandleScope scope(isolate);
20146 auto global = context->Global();
20147 auto sig_obj = FunctionTemplate::New(isolate);
20148 auto sig = v8::Signature::New(isolate, sig_obj);
20149 for (int i = 0; i < 4; ++i) {
20150 auto temp = FunctionTemplate::New(isolate);
20151 temp->Inherit(sig_obj);
20154 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20155 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20156 global->Set(v8_str("x"), x->GetFunction());
20157 CompileRun("var s = new sig_obj();");
20159 TryCatch try_catch(isolate);
20161 CHECK(try_catch.HasCaught());
20164 TryCatch try_catch(isolate);
20165 CompileRun("x.call(1)");
20166 CHECK(try_catch.HasCaught());
20169 TryCatch try_catch(isolate);
20170 auto result = CompileRun("s.x = x; s.x()");
20171 CHECK(!try_catch.HasCaught());
20172 CHECK_EQ(42, result->Int32Value());
20175 TryCatch try_catch(isolate);
20176 auto result = CompileRun("x.call(s)");
20177 CHECK(!try_catch.HasCaught());
20178 CHECK_EQ(42, result->Int32Value());
20183 TEST(PrototypeSignatureCheck) {
20184 LocalContext context;
20185 auto isolate = context->GetIsolate();
20186 v8::HandleScope scope(isolate);
20187 auto global = context->Global();
20188 auto sig_obj = FunctionTemplate::New(isolate);
20189 sig_obj->SetHiddenPrototype(true);
20190 auto sig = v8::Signature::New(isolate, sig_obj);
20191 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20192 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20193 global->Set(v8_str("x"), x->GetFunction());
20194 CompileRun("s = {}; s.__proto__ = new sig_obj();");
20196 TryCatch try_catch(isolate);
20198 CHECK(try_catch.HasCaught());
20201 TryCatch try_catch(isolate);
20202 CompileRun("x.call(1)");
20203 CHECK(try_catch.HasCaught());
20206 TryCatch try_catch(isolate);
20207 auto result = CompileRun("s.x = x; s.x()");
20208 CHECK(!try_catch.HasCaught());
20209 CHECK_EQ(42, result->Int32Value());
20212 TryCatch try_catch(isolate);
20213 auto result = CompileRun("x.call(s)");
20214 CHECK(!try_catch.HasCaught());
20215 CHECK_EQ(42, result->Int32Value());
20220 static const char* last_event_message;
20221 static int last_event_status;
20222 void StoringEventLoggerCallback(const char* message, int status) {
20223 last_event_message = message;
20224 last_event_status = status;
20228 TEST(EventLogging) {
20229 v8::Isolate* isolate = CcTest::isolate();
20230 isolate->SetEventLogger(StoringEventLoggerCallback);
20231 v8::internal::HistogramTimer histogramTimer(
20232 "V8.Test", 0, 10000, v8::internal::HistogramTimer::MILLISECOND, 50,
20233 reinterpret_cast<v8::internal::Isolate*>(isolate));
20234 histogramTimer.Start();
20235 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20236 CHECK_EQ(0, last_event_status);
20237 histogramTimer.Stop();
20238 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20239 CHECK_EQ(1, last_event_status);
20244 LocalContext context;
20245 v8::Isolate* isolate = context->GetIsolate();
20246 v8::HandleScope scope(isolate);
20247 Handle<Object> global = context->Global();
20250 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20251 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
20252 Handle<v8::Promise> p = pr->GetPromise();
20253 Handle<v8::Promise> r = rr->GetPromise();
20254 CHECK_EQ(isolate, p->GetIsolate());
20256 // IsPromise predicate.
20257 CHECK(p->IsPromise());
20258 CHECK(r->IsPromise());
20259 Handle<Value> o = v8::Object::New(isolate);
20260 CHECK(!o->IsPromise());
20262 // Resolution and rejection.
20263 pr->Resolve(v8::Integer::New(isolate, 1));
20264 CHECK(p->IsPromise());
20265 rr->Reject(v8::Integer::New(isolate, 2));
20266 CHECK(r->IsPromise());
20268 // Chaining non-pending promises.
20272 "function f1(x) { x1 = x; return x+1 };\n"
20273 "function f2(x) { x2 = x; return x+1 };\n");
20274 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20275 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20278 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20279 isolate->RunMicrotasks();
20280 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20283 isolate->RunMicrotasks();
20284 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20287 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20288 isolate->RunMicrotasks();
20289 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20292 isolate->RunMicrotasks();
20293 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20295 // Chaining pending promises.
20296 CompileRun("x1 = x2 = 0;");
20297 pr = v8::Promise::Resolver::New(isolate);
20298 rr = v8::Promise::Resolver::New(isolate);
20300 pr->GetPromise()->Chain(f1);
20301 rr->GetPromise()->Catch(f2);
20302 isolate->RunMicrotasks();
20303 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20304 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20306 pr->Resolve(v8::Integer::New(isolate, 1));
20307 rr->Reject(v8::Integer::New(isolate, 2));
20308 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20309 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20311 isolate->RunMicrotasks();
20312 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20313 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20316 CompileRun("x1 = x2 = 0;");
20317 pr = v8::Promise::Resolver::New(isolate);
20318 pr->GetPromise()->Chain(f1)->Chain(f2);
20319 pr->Resolve(v8::Integer::New(isolate, 3));
20320 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20321 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20322 isolate->RunMicrotasks();
20323 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20324 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20326 CompileRun("x1 = x2 = 0;");
20327 rr = v8::Promise::Resolver::New(isolate);
20328 rr->GetPromise()->Catch(f1)->Chain(f2);
20329 rr->Reject(v8::Integer::New(isolate, 3));
20330 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20331 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20332 isolate->RunMicrotasks();
20333 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20334 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20338 TEST(PromiseThen) {
20339 LocalContext context;
20340 v8::Isolate* isolate = context->GetIsolate();
20341 v8::HandleScope scope(isolate);
20342 Handle<Object> global = context->Global();
20345 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20346 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
20347 Handle<v8::Promise> p = pr->GetPromise();
20348 Handle<v8::Promise> q = qr->GetPromise();
20350 CHECK(p->IsPromise());
20351 CHECK(q->IsPromise());
20353 pr->Resolve(v8::Integer::New(isolate, 1));
20356 // Chaining non-pending promises.
20360 "function f1(x) { x1 = x; return x+1 };\n"
20361 "function f2(x) { x2 = x; return x+1 };\n");
20362 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20363 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20367 CHECK(global->Get(v8_str("x1"))->IsNumber());
20368 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20369 isolate->RunMicrotasks();
20370 CHECK(!global->Get(v8_str("x1"))->IsNumber());
20371 CHECK(p->Equals(global->Get(v8_str("x1"))));
20374 CompileRun("x1 = x2 = 0;");
20376 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20377 isolate->RunMicrotasks();
20378 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20381 CompileRun("x1 = x2 = 0;");
20382 pr = v8::Promise::Resolver::New(isolate);
20383 qr = v8::Promise::Resolver::New(isolate);
20386 qr->GetPromise()->Then(f1)->Then(f2);
20388 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20389 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20390 isolate->RunMicrotasks();
20391 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20392 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20394 pr->Resolve(v8::Integer::New(isolate, 3));
20396 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20397 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20398 isolate->RunMicrotasks();
20399 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20400 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20404 TEST(DisallowJavascriptExecutionScope) {
20405 LocalContext context;
20406 v8::Isolate* isolate = context->GetIsolate();
20407 v8::HandleScope scope(isolate);
20408 v8::Isolate::DisallowJavascriptExecutionScope no_js(
20409 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20414 TEST(AllowJavascriptExecutionScope) {
20415 LocalContext context;
20416 v8::Isolate* isolate = context->GetIsolate();
20417 v8::HandleScope scope(isolate);
20418 v8::Isolate::DisallowJavascriptExecutionScope no_js(
20419 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20420 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20421 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20422 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
20428 TEST(ThrowOnJavascriptExecution) {
20429 LocalContext context;
20430 v8::Isolate* isolate = context->GetIsolate();
20431 v8::HandleScope scope(isolate);
20432 v8::TryCatch try_catch(isolate);
20433 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20434 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20436 CHECK(try_catch.HasCaught());
20440 TEST(Regress354123) {
20441 LocalContext current;
20442 v8::Isolate* isolate = current->GetIsolate();
20443 v8::HandleScope scope(isolate);
20445 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
20446 templ->SetAccessCheckCallbacks(AccessCounter, NULL);
20447 current->Global()->Set(v8_str("friend"), templ->NewInstance());
20449 // Test access using __proto__ from the prototype chain.
20451 CompileRun("friend.__proto__ = {};");
20452 CHECK_EQ(2, access_count);
20453 CompileRun("friend.__proto__;");
20454 CHECK_EQ(4, access_count);
20456 // Test access using __proto__ as a hijacked function (A).
20458 CompileRun("var p = Object.prototype;"
20459 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
20460 "f.call(friend, {});");
20461 CHECK_EQ(1, access_count);
20462 CompileRun("var p = Object.prototype;"
20463 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
20464 "f.call(friend);");
20465 CHECK_EQ(2, access_count);
20467 // Test access using __proto__ as a hijacked function (B).
20469 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
20470 "f.call(friend, {});");
20471 CHECK_EQ(1, access_count);
20472 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
20473 "f.call(friend);");
20474 CHECK_EQ(2, access_count);
20476 // Test access using Object.setPrototypeOf reflective method.
20478 CompileRun("Object.setPrototypeOf(friend, {});");
20479 CHECK_EQ(1, access_count);
20480 CompileRun("Object.getPrototypeOf(friend);");
20481 CHECK_EQ(2, access_count);
20485 TEST(CaptureStackTraceForStackOverflow) {
20486 v8::internal::FLAG_stack_size = 150;
20487 LocalContext current;
20488 v8::Isolate* isolate = current->GetIsolate();
20489 v8::HandleScope scope(isolate);
20490 V8::SetCaptureStackTraceForUncaughtExceptions(
20491 true, 10, v8::StackTrace::kDetailed);
20492 v8::TryCatch try_catch(isolate);
20493 CompileRun("(function f(x) { f(x+1); })(0)");
20494 CHECK(try_catch.HasCaught());
20498 TEST(ScriptNameAndLineNumber) {
20500 v8::Isolate* isolate = env->GetIsolate();
20501 v8::HandleScope scope(isolate);
20502 const char* url = "http://www.foo.com/foo.js";
20503 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
20504 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
20505 Local<Script> script = v8::ScriptCompiler::Compile(
20506 isolate, &script_source);
20507 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
20508 CHECK(!script_name.IsEmpty());
20509 CHECK(script_name->IsString());
20510 String::Utf8Value utf8_name(script_name);
20511 CHECK_EQ(0, strcmp(url, *utf8_name));
20512 int line_number = script->GetUnboundScript()->GetLineNumber(0);
20513 CHECK_EQ(13, line_number);
20516 void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
20517 const char* expected_source_mapping_url) {
20518 if (expected_source_url != NULL) {
20519 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
20520 CHECK_EQ(0, strcmp(expected_source_url, *url));
20522 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
20524 if (expected_source_mapping_url != NULL) {
20525 v8::String::Utf8Value url(
20526 script->GetUnboundScript()->GetSourceMappingURL());
20527 CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
20529 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
20533 void SourceURLHelper(const char* source, const char* expected_source_url,
20534 const char* expected_source_mapping_url) {
20535 Local<Script> script = v8_compile(source);
20536 CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
20540 TEST(ScriptSourceURLAndSourceMappingURL) {
20542 v8::Isolate* isolate = env->GetIsolate();
20543 v8::HandleScope scope(isolate);
20544 SourceURLHelper("function foo() {}\n"
20545 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
20546 SourceURLHelper("function foo() {}\n"
20547 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
20549 // Both sourceURL and sourceMappingURL.
20550 SourceURLHelper("function foo() {}\n"
20551 "//# sourceURL=bar3.js\n"
20552 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
20554 // Two source URLs; the first one is ignored.
20555 SourceURLHelper("function foo() {}\n"
20556 "//# sourceURL=ignoreme.js\n"
20557 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
20558 SourceURLHelper("function foo() {}\n"
20559 "//# sourceMappingURL=ignoreme.js\n"
20560 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
20562 // SourceURL or sourceMappingURL in the middle of the script.
20563 SourceURLHelper("function foo() {}\n"
20564 "//# sourceURL=bar7.js\n"
20565 "function baz() {}\n", "bar7.js", NULL);
20566 SourceURLHelper("function foo() {}\n"
20567 "//# sourceMappingURL=bar8.js\n"
20568 "function baz() {}\n", NULL, "bar8.js");
20570 // Too much whitespace.
20571 SourceURLHelper("function foo() {}\n"
20572 "//# sourceURL=bar9.js\n"
20573 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
20574 SourceURLHelper("function foo() {}\n"
20575 "//# sourceURL =bar11.js\n"
20576 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
20578 // Disallowed characters in value.
20579 SourceURLHelper("function foo() {}\n"
20580 "//# sourceURL=bar13 .js \n"
20581 "//# sourceMappingURL=bar14 .js \n",
20583 SourceURLHelper("function foo() {}\n"
20584 "//# sourceURL=bar15\t.js \n"
20585 "//# sourceMappingURL=bar16\t.js \n",
20587 SourceURLHelper("function foo() {}\n"
20588 "//# sourceURL=bar17'.js \n"
20589 "//# sourceMappingURL=bar18'.js \n",
20591 SourceURLHelper("function foo() {}\n"
20592 "//# sourceURL=bar19\".js \n"
20593 "//# sourceMappingURL=bar20\".js \n",
20596 // Not too much whitespace.
20597 SourceURLHelper("function foo() {}\n"
20598 "//# sourceURL= bar21.js \n"
20599 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
20603 TEST(GetOwnPropertyDescriptor) {
20605 v8::Isolate* isolate = env->GetIsolate();
20606 v8::HandleScope scope(isolate);
20608 "var x = { value : 13};"
20609 "Object.defineProperty(x, 'p0', {value : 12});"
20610 "Object.defineProperty(x, 'p1', {"
20611 " set : function(value) { this.value = value; },"
20612 " get : function() { return this.value; },"
20614 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
20615 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
20616 CHECK(desc->IsUndefined());
20617 desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
20618 CHECK(v8_num(12)->Equals(Local<Object>::Cast(desc)->Get(v8_str("value"))));
20619 desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
20620 Local<Function> set =
20621 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
20622 Local<Function> get =
20623 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
20624 CHECK(v8_num(13)->Equals(get->Call(x, 0, NULL)));
20625 Handle<Value> args[] = { v8_num(14) };
20626 set->Call(x, 1, args);
20627 CHECK(v8_num(14)->Equals(get->Call(x, 0, NULL)));
20631 TEST(Regress411877) {
20632 v8::Isolate* isolate = CcTest::isolate();
20633 v8::HandleScope handle_scope(isolate);
20634 v8::Handle<v8::ObjectTemplate> object_template =
20635 v8::ObjectTemplate::New(isolate);
20636 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
20638 v8::Handle<Context> context = Context::New(isolate);
20639 v8::Context::Scope context_scope(context);
20641 context->Global()->Set(v8_str("o"), object_template->NewInstance());
20642 CompileRun("Object.getOwnPropertyNames(o)");
20646 TEST(GetHiddenPropertyTableAfterAccessCheck) {
20647 v8::Isolate* isolate = CcTest::isolate();
20648 v8::HandleScope handle_scope(isolate);
20649 v8::Handle<v8::ObjectTemplate> object_template =
20650 v8::ObjectTemplate::New(isolate);
20651 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
20653 v8::Handle<Context> context = Context::New(isolate);
20654 v8::Context::Scope context_scope(context);
20656 v8::Handle<v8::Object> obj = object_template->NewInstance();
20657 obj->Set(v8_str("key"), v8_str("value"));
20658 obj->Delete(v8_str("key"));
20660 obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
20664 TEST(Regress411793) {
20665 v8::Isolate* isolate = CcTest::isolate();
20666 v8::HandleScope handle_scope(isolate);
20667 v8::Handle<v8::ObjectTemplate> object_template =
20668 v8::ObjectTemplate::New(isolate);
20669 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
20671 v8::Handle<Context> context = Context::New(isolate);
20672 v8::Context::Scope context_scope(context);
20674 context->Global()->Set(v8_str("o"), object_template->NewInstance());
20676 "Object.defineProperty(o, 'key', "
20677 " { get: function() {}, set: function() {} });");
20680 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
20682 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
20684 virtual size_t GetMoreData(const uint8_t** src) {
20685 // Unlike in real use cases, this function will never block.
20686 if (chunks_[index_] == NULL) {
20689 // Copy the data, since the caller takes ownership of it.
20690 size_t len = strlen(chunks_[index_]);
20691 // We don't need to zero-terminate since we return the length.
20692 uint8_t* copy = new uint8_t[len];
20693 memcpy(copy, chunks_[index_], len);
20699 // Helper for constructing a string from chunks (the compilation needs it
20701 static char* FullSourceString(const char** chunks) {
20702 size_t total_len = 0;
20703 for (size_t i = 0; chunks[i] != NULL; ++i) {
20704 total_len += strlen(chunks[i]);
20706 char* full_string = new char[total_len + 1];
20708 for (size_t i = 0; chunks[i] != NULL; ++i) {
20709 size_t len = strlen(chunks[i]);
20710 memcpy(full_string + offset, chunks[i], len);
20713 full_string[total_len] = 0;
20714 return full_string;
20718 const char** chunks_;
20723 // Helper function for running streaming tests.
20724 void RunStreamingTest(const char** chunks,
20725 v8::ScriptCompiler::StreamedSource::Encoding encoding =
20726 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
20727 bool expected_success = true,
20728 const char* expected_source_url = NULL,
20729 const char* expected_source_mapping_url = NULL) {
20731 v8::Isolate* isolate = env->GetIsolate();
20732 v8::HandleScope scope(isolate);
20733 v8::TryCatch try_catch(isolate);
20735 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
20737 v8::ScriptCompiler::ScriptStreamingTask* task =
20738 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
20740 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
20741 // task here in the main thread.
20745 // Possible errors are only produced while compiling.
20746 CHECK_EQ(false, try_catch.HasCaught());
20748 v8::ScriptOrigin origin(v8_str("http://foo.com"));
20749 char* full_source = TestSourceStream::FullSourceString(chunks);
20750 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
20751 isolate, &source, v8_str(full_source), origin);
20752 if (expected_success) {
20753 CHECK(!script.IsEmpty());
20754 v8::Handle<Value> result(script->Run());
20755 // All scripts are supposed to return the fixed value 13 when ran.
20756 CHECK_EQ(13, result->Int32Value());
20757 CheckMagicComments(script, expected_source_url,
20758 expected_source_mapping_url);
20760 CHECK(script.IsEmpty());
20761 CHECK(try_catch.HasCaught());
20763 delete[] full_source;
20767 TEST(StreamingSimpleScript) {
20768 // This script is unrealistically small, since no one chunk is enough to fill
20769 // the backing buffer of Scanner, let alone overflow it.
20770 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
20772 RunStreamingTest(chunks);
20776 TEST(StreamingBiggerScript) {
20777 const char* chunk1 =
20778 "function foo() {\n"
20779 " // Make this chunk sufficiently long so that it will overflow the\n"
20780 " // backing buffer of the Scanner.\n"
20782 " var result = 0;\n"
20783 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20785 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20787 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20789 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
20790 " return result;\n"
20792 const char* chunks[] = {chunk1, "foo(); ", NULL};
20793 RunStreamingTest(chunks);
20797 TEST(StreamingScriptWithParseError) {
20798 // Test that parse errors from streamed scripts are propagated correctly.
20801 " // This will result in a parse error.\n"
20802 " var if else then foo";
20803 char chunk2[] = " 13\n";
20804 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20806 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
20809 // Test that the next script succeeds normally.
20812 " // This will be parsed successfully.\n"
20813 " function foo() { return ";
20814 char chunk2[] = " 13; }\n";
20815 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20817 RunStreamingTest(chunks);
20822 TEST(StreamingUtf8Script) {
20823 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
20825 const char* chunk1 =
20826 "function foo() {\n"
20827 " // This function will contain an UTF-8 character which is not in\n"
20829 " var foob\xec\x92\x81r = 13;\n"
20830 " return foob\xec\x92\x81r;\n"
20832 const char* chunks[] = {chunk1, "foo(); ", NULL};
20833 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20837 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
20838 // A sanity check to prove that the approach of splitting UTF-8
20839 // characters is correct. Here is an UTF-8 character which will take three
20841 const char* reference = "\xec\x92\x81";
20842 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
20845 "function foo() {\n"
20846 " // This function will contain an UTF-8 character which is not in\n"
20851 " return foob\xec\x92\x81r;\n"
20853 for (int i = 0; i < 3; ++i) {
20854 chunk2[i] = reference[i];
20856 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20857 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20861 TEST(StreamingUtf8ScriptWithSplitCharacters) {
20862 // Stream data where a multi-byte UTF-8 character is split between two data
20864 const char* reference = "\xec\x92\x81";
20866 "function foo() {\n"
20867 " // This function will contain an UTF-8 character which is not in\n"
20872 " return foob\xec\x92\x81r;\n"
20874 chunk1[strlen(chunk1) - 1] = reference[0];
20875 chunk2[0] = reference[1];
20876 chunk2[1] = reference[2];
20877 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
20878 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20882 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
20883 // Tests edge cases which should still be decoded correctly.
20885 // Case 1: a chunk contains only bytes for a split character (and no other
20886 // data). This kind of a chunk would be exceptionally small, but we should
20887 // still decode it correctly.
20888 const char* reference = "\xec\x92\x81";
20889 // The small chunk is at the beginning of the split character
20892 "function foo() {\n"
20893 " // This function will contain an UTF-8 character which is not in\n"
20896 char chunk2[] = "XX";
20899 " return foob\xec\x92\x81r;\n"
20901 chunk2[0] = reference[0];
20902 chunk2[1] = reference[1];
20903 chunk3[0] = reference[2];
20904 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
20905 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20907 // The small chunk is at the end of a character
20910 "function foo() {\n"
20911 " // This function will contain an UTF-8 character which is not in\n"
20914 char chunk2[] = "XX";
20917 " return foob\xec\x92\x81r;\n"
20919 chunk1[strlen(chunk1) - 1] = reference[0];
20920 chunk2[0] = reference[1];
20921 chunk2[1] = reference[2];
20922 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
20923 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20925 // Case 2: the script ends with a multi-byte character. Make sure that it's
20926 // decoded correctly and not just ignored.
20929 "var foob\xec\x92\x81 = 13;\n"
20930 "foob\xec\x92\x81";
20931 const char* chunks[] = {chunk1, NULL};
20932 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
20937 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
20938 // Test cases where a UTF-8 character is split over several chunks. Those
20939 // cases are not supported (the embedder should give the data in big enough
20940 // chunks), but we shouldn't crash, just produce a parse error.
20941 const char* reference = "\xec\x92\x81";
20943 "function foo() {\n"
20944 " // This function will contain an UTF-8 character which is not in\n"
20947 char chunk2[] = "X";
20950 " return foob\xec\x92\x81r;\n"
20952 chunk1[strlen(chunk1) - 1] = reference[0];
20953 chunk2[0] = reference[1];
20954 chunk3[0] = reference[2];
20955 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
20957 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
20961 TEST(StreamingProducesParserCache) {
20962 i::FLAG_min_preparse_length = 0;
20963 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
20967 v8::Isolate* isolate = env->GetIsolate();
20968 v8::HandleScope scope(isolate);
20970 v8::ScriptCompiler::StreamedSource source(
20971 new TestSourceStream(chunks),
20972 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
20973 v8::ScriptCompiler::ScriptStreamingTask* task =
20974 v8::ScriptCompiler::StartStreamingScript(
20975 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
20977 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
20978 // task here in the main thread.
20982 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
20983 CHECK(cached_data != NULL);
20984 CHECK(cached_data->data != NULL);
20985 CHECK(!cached_data->rejected);
20986 CHECK_GT(cached_data->length, 0);
20990 TEST(StreamingWithDebuggingDoesNotProduceParserCache) {
20991 // If the debugger is active, we should just not produce parser cache at
20992 // all. This is a regeression test: We used to produce a parser cache without
20993 // any data in it (just headers).
20994 i::FLAG_min_preparse_length = 0;
20995 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
20999 v8::Isolate* isolate = env->GetIsolate();
21000 v8::HandleScope scope(isolate);
21002 // Make the debugger active by setting a breakpoint.
21003 CompileRun("function break_here() { }");
21004 i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
21005 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("break_here"))));
21007 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
21009 debug->SetBreakPoint(func, i::Handle<i::Object>(v8::internal::Smi::FromInt(1),
21010 CcTest::i_isolate()),
21013 v8::ScriptCompiler::StreamedSource source(
21014 new TestSourceStream(chunks),
21015 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21016 v8::ScriptCompiler::ScriptStreamingTask* task =
21017 v8::ScriptCompiler::StartStreamingScript(
21018 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
21020 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
21021 // task here in the main thread.
21025 // Check that we got no cached data.
21026 CHECK(source.GetCachedData() == NULL);
21031 TEST(StreamingScriptWithInvalidUtf8) {
21032 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
21033 // chunk don't produce a crash.
21034 const char* reference = "\xec\x92\x81\x80\x80";
21036 "function foo() {\n"
21037 " // This function will contain an UTF-8 character which is not in\n"
21039 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
21042 " return foob\xec\x92\x81\x80\x80r;\n"
21044 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
21046 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21047 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
21051 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
21052 // Regression test: Stream data where there are several multi-byte UTF-8
21053 // characters in a sequence and one of them is split between two data chunks.
21054 const char* reference = "\xec\x92\x81";
21056 "function foo() {\n"
21057 " // This function will contain an UTF-8 character which is not in\n"
21059 " var foob\xec\x92\x81X";
21062 " return foob\xec\x92\x81\xec\x92\x81r;\n"
21064 chunk1[strlen(chunk1) - 1] = reference[0];
21065 chunk2[0] = reference[1];
21066 chunk2[1] = reference[2];
21067 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21068 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21072 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
21073 // Another regression test, similar to the previous one. The difference is
21074 // that the split character is not the last one in the sequence.
21075 const char* reference = "\xec\x92\x81";
21077 "function foo() {\n"
21078 " // This function will contain an UTF-8 character which is not in\n"
21082 "XX\xec\x92\x81r = 13;\n"
21083 " return foob\xec\x92\x81\xec\x92\x81r;\n"
21085 chunk1[strlen(chunk1) - 1] = reference[0];
21086 chunk2[0] = reference[1];
21087 chunk2[1] = reference[2];
21088 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21089 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21093 TEST(StreamingWithHarmonyScopes) {
21094 // Don't use RunStreamingTest here so that both scripts get to use the same
21095 // LocalContext and HandleScope.
21097 v8::Isolate* isolate = env->GetIsolate();
21098 v8::HandleScope scope(isolate);
21100 // First, run a script with a let variable.
21101 CompileRun("\"use strict\"; let x = 1;");
21103 // Then stream a script which (erroneously) tries to introduce the same
21105 const char* chunks[] = {"\"use strict\"; let x = 2;", NULL};
21107 v8::TryCatch try_catch(isolate);
21108 v8::ScriptCompiler::StreamedSource source(
21109 new TestSourceStream(chunks),
21110 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21111 v8::ScriptCompiler::ScriptStreamingTask* task =
21112 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
21116 // Parsing should succeed (the script will be parsed and compiled in a context
21117 // independent way, so the error is not detected).
21118 CHECK_EQ(false, try_catch.HasCaught());
21120 v8::ScriptOrigin origin(v8_str("http://foo.com"));
21121 char* full_source = TestSourceStream::FullSourceString(chunks);
21122 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
21123 isolate, &source, v8_str(full_source), origin);
21124 CHECK(!script.IsEmpty());
21125 CHECK_EQ(false, try_catch.HasCaught());
21127 // Running the script exposes the error.
21128 v8::Handle<Value> result(script->Run());
21129 CHECK(result.IsEmpty());
21130 CHECK(try_catch.HasCaught());
21131 delete[] full_source;
21136 v8::Isolate::CreateParams create_params;
21137 create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
21139 const char* source = "Math.sqrt(4)";
21140 const char* origin = "code cache test";
21141 v8::ScriptCompiler::CachedData* cache;
21143 v8::Isolate* isolate1 = v8::Isolate::New(create_params);
21145 v8::Isolate::Scope iscope(isolate1);
21146 v8::HandleScope scope(isolate1);
21147 v8::Local<v8::Context> context = v8::Context::New(isolate1);
21148 v8::Context::Scope cscope(context);
21149 v8::Local<v8::String> source_string = v8_str(source);
21150 v8::ScriptOrigin script_origin(v8_str(origin));
21151 v8::ScriptCompiler::Source source(source_string, script_origin);
21152 v8::ScriptCompiler::CompileOptions option =
21153 v8::ScriptCompiler::kProduceCodeCache;
21154 v8::ScriptCompiler::Compile(context, &source, option).ToLocalChecked();
21155 int length = source.GetCachedData()->length;
21156 uint8_t* cache_data = new uint8_t[length];
21157 memcpy(cache_data, source.GetCachedData()->data, length);
21158 cache = new v8::ScriptCompiler::CachedData(
21159 cache_data, length, v8::ScriptCompiler::CachedData::BufferOwned);
21161 isolate1->Dispose();
21163 v8::Isolate* isolate2 = v8::Isolate::New(create_params);
21165 v8::Isolate::Scope iscope(isolate2);
21166 v8::HandleScope scope(isolate2);
21167 v8::Local<v8::Context> context = v8::Context::New(isolate2);
21168 v8::Context::Scope cscope(context);
21169 v8::Local<v8::String> source_string = v8_str(source);
21170 v8::ScriptOrigin script_origin(v8_str(origin));
21171 v8::ScriptCompiler::Source source(source_string, script_origin, cache);
21172 v8::ScriptCompiler::CompileOptions option =
21173 v8::ScriptCompiler::kConsumeCodeCache;
21174 v8::Local<v8::Script> script;
21176 i::DisallowCompilation no_compile(
21177 reinterpret_cast<i::Isolate*>(isolate2));
21178 script = v8::ScriptCompiler::Compile(context, &source, option)
21181 CHECK_EQ(2, script->Run()->ToInt32(isolate2)->Int32Value());
21183 isolate2->Dispose();
21187 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
21188 const char* garbage = "garbage garbage garbage garbage garbage garbage";
21189 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
21191 v8::ScriptCompiler::CachedData* cached_data =
21192 new v8::ScriptCompiler::CachedData(data, length);
21193 DCHECK(!cached_data->rejected);
21194 v8::ScriptOrigin origin(v8_str("origin"));
21195 v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
21196 v8::Handle<v8::Script> script =
21197 v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
21198 CHECK(cached_data->rejected);
21199 CHECK_EQ(42, script->Run()->Int32Value());
21203 TEST(InvalidCacheData) {
21204 v8::V8::Initialize();
21205 v8::HandleScope scope(CcTest::isolate());
21206 LocalContext context;
21207 TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
21208 TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
21212 TEST(ParserCacheRejectedGracefully) {
21213 i::FLAG_min_preparse_length = 0;
21214 v8::V8::Initialize();
21215 v8::HandleScope scope(CcTest::isolate());
21216 LocalContext context;
21217 // Produce valid cached data.
21218 v8::ScriptOrigin origin(v8_str("origin"));
21219 v8::Local<v8::String> source_str = v8_str("function foo() {}");
21220 v8::ScriptCompiler::Source source(source_str, origin);
21221 v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
21222 CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
21223 CHECK(!script.IsEmpty());
21224 const v8::ScriptCompiler::CachedData* original_cached_data =
21225 source.GetCachedData();
21226 CHECK(original_cached_data != NULL);
21227 CHECK(original_cached_data->data != NULL);
21228 CHECK(!original_cached_data->rejected);
21229 CHECK_GT(original_cached_data->length, 0);
21230 // Recompiling the same script with it won't reject the data.
21232 v8::ScriptCompiler::Source source_with_cached_data(
21233 source_str, origin,
21234 new v8::ScriptCompiler::CachedData(original_cached_data->data,
21235 original_cached_data->length));
21236 v8::Handle<v8::Script> script =
21237 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21238 v8::ScriptCompiler::kConsumeParserCache);
21239 CHECK(!script.IsEmpty());
21240 const v8::ScriptCompiler::CachedData* new_cached_data =
21241 source_with_cached_data.GetCachedData();
21242 CHECK(new_cached_data != NULL);
21243 CHECK(!new_cached_data->rejected);
21245 // Compile an incompatible script with the cached data. The new script doesn't
21246 // have the same starting position for the function as the old one, so the old
21247 // cached data will be incompatible with it and will be rejected.
21249 v8::Local<v8::String> incompatible_source_str =
21250 v8_str(" function foo() {}");
21251 v8::ScriptCompiler::Source source_with_cached_data(
21252 incompatible_source_str, origin,
21253 new v8::ScriptCompiler::CachedData(original_cached_data->data,
21254 original_cached_data->length));
21255 v8::Handle<v8::Script> script =
21256 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21257 v8::ScriptCompiler::kConsumeParserCache);
21258 CHECK(!script.IsEmpty());
21259 const v8::ScriptCompiler::CachedData* new_cached_data =
21260 source_with_cached_data.GetCachedData();
21261 CHECK(new_cached_data != NULL);
21262 CHECK(new_cached_data->rejected);
21267 TEST(StringConcatOverflow) {
21268 v8::V8::Initialize();
21269 v8::HandleScope scope(CcTest::isolate());
21270 RandomLengthOneByteResource* r =
21271 new RandomLengthOneByteResource(i::String::kMaxLength);
21272 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
21273 CHECK(!str.IsEmpty());
21274 v8::TryCatch try_catch(CcTest::isolate());
21275 v8::Local<v8::String> result = v8::String::Concat(str, str);
21276 CHECK(result.IsEmpty());
21277 CHECK(!try_catch.HasCaught());
21281 TEST(TurboAsmDisablesNeuter) {
21282 v8::V8::Initialize();
21283 v8::HandleScope scope(CcTest::isolate());
21284 LocalContext context;
21285 #if V8_TURBOFAN_TARGET
21286 bool should_be_neuterable = !i::FLAG_turbo_asm;
21288 bool should_be_neuterable = true;
21291 "function Module(stdlib, foreign, heap) {"
21293 " var MEM32 = new stdlib.Int32Array(heap);"
21294 " function load() { return MEM32[0]; }"
21295 " return { load: load };"
21297 "var buffer = new ArrayBuffer(4);"
21298 "Module(this, {}, buffer).load();"
21301 i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF.
21302 v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
21303 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21305 const char* store =
21306 "function Module(stdlib, foreign, heap) {"
21308 " var MEM32 = new stdlib.Int32Array(heap);"
21309 " function store() { MEM32[0] = 0; }"
21310 " return { store: store };"
21312 "var buffer = new ArrayBuffer(4);"
21313 "Module(this, {}, buffer).store();"
21316 i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF.
21317 result = CompileRun(store).As<v8::ArrayBuffer>();
21318 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21322 TEST(GetPrototypeAccessControl) {
21323 i::FLAG_allow_natives_syntax = true;
21324 v8::Isolate* isolate = CcTest::isolate();
21325 v8::HandleScope handle_scope(isolate);
21328 v8::Handle<v8::ObjectTemplate> obj_template =
21329 v8::ObjectTemplate::New(isolate);
21330 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
21332 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
21335 v8::TryCatch try_catch(isolate);
21337 "function f() { %_GetPrototype(prohibited); }"
21338 "%OptimizeFunctionOnNextCall(f);"
21340 CHECK(try_catch.HasCaught());
21345 TEST(GetPrototypeHidden) {
21346 i::FLAG_allow_natives_syntax = true;
21347 v8::Isolate* isolate = CcTest::isolate();
21348 v8::HandleScope handle_scope(isolate);
21351 Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
21352 t->SetHiddenPrototype(true);
21353 Handle<Object> proto = t->GetFunction()->NewInstance();
21354 Handle<Object> object = Object::New(isolate);
21355 Handle<Object> proto2 = Object::New(isolate);
21356 object->SetPrototype(proto);
21357 proto->SetPrototype(proto2);
21359 env->Global()->Set(v8_str("object"), object);
21360 env->Global()->Set(v8_str("proto"), proto);
21361 env->Global()->Set(v8_str("proto2"), proto2);
21363 v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
21364 CHECK(result->Equals(proto2));
21366 result = CompileRun(
21367 "function f() { return %_GetPrototype(object); }"
21368 "%OptimizeFunctionOnNextCall(f);"
21370 CHECK(result->Equals(proto2));
21374 TEST(ClassPrototypeCreationContext) {
21375 v8::Isolate* isolate = CcTest::isolate();
21376 v8::HandleScope handle_scope(isolate);
21379 Handle<Object> result = Handle<Object>::Cast(
21380 CompileRun("'use strict'; class Example { }; Example.prototype"));
21381 CHECK(env.local() == result->CreationContext());
21385 TEST(SimpleStreamingScriptWithSourceURL) {
21386 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
21387 "//# sourceURL=bar2.js\n", NULL};
21388 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21393 TEST(StreamingScriptWithSplitSourceURL) {
21394 const char* chunks[] = {"function foo() { ret", "urn 13; } f",
21395 "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
21396 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21401 TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
21402 const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
21403 " sourceMappingURL=bar2.js\n", "foo();", NULL};
21404 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
21409 TEST(NewStringRangeError) {
21410 v8::Isolate* isolate = CcTest::isolate();
21411 v8::HandleScope handle_scope(isolate);
21412 const int length = i::String::kMaxLength + 1;
21413 const int buffer_size = length * sizeof(uint16_t);
21414 void* buffer = malloc(buffer_size);
21415 if (buffer == NULL) return;
21416 memset(buffer, 'A', buffer_size);
21418 v8::TryCatch try_catch(isolate);
21419 char* data = reinterpret_cast<char*>(buffer);
21420 CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString,
21421 length).IsEmpty());
21422 CHECK(!try_catch.HasCaught());
21425 v8::TryCatch try_catch(isolate);
21426 uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
21427 CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString,
21428 length).IsEmpty());
21429 CHECK(!try_catch.HasCaught());
21432 v8::TryCatch try_catch(isolate);
21433 uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
21434 CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString,
21435 length).IsEmpty());
21436 CHECK(!try_catch.HasCaught());
21442 TEST(SealHandleScope) {
21443 v8::Isolate* isolate = CcTest::isolate();
21444 v8::HandleScope handle_scope(isolate);
21447 v8::SealHandleScope seal(isolate);
21450 v8::Local<v8::Object> obj = v8::Object::New(isolate);
21456 TEST(SealHandleScopeNested) {
21457 v8::Isolate* isolate = CcTest::isolate();
21458 v8::HandleScope handle_scope(isolate);
21461 v8::SealHandleScope seal(isolate);
21464 v8::HandleScope handle_scope(isolate);
21467 v8::Local<v8::Object> obj = v8::Object::New(isolate);
21474 static bool access_was_called = false;
21477 static bool AccessAlwaysAllowedWithFlag(Local<v8::Object> global,
21478 Local<Value> name, v8::AccessType type,
21479 Local<Value> data) {
21480 access_was_called = true;
21485 static bool AccessAlwaysBlockedWithFlag(Local<v8::Object> global,
21486 Local<Value> name, v8::AccessType type,
21487 Local<Value> data) {
21488 access_was_called = true;
21493 TEST(StrongModeAccessCheckAllowed) {
21494 i::FLAG_strong_mode = true;
21495 v8::Isolate* isolate = CcTest::isolate();
21496 v8::HandleScope handle_scope(isolate);
21497 v8::Handle<Value> value;
21498 access_was_called = false;
21500 v8::Handle<v8::ObjectTemplate> obj_template =
21501 v8::ObjectTemplate::New(isolate);
21503 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
21504 obj_template->SetAccessCheckCallbacks(AccessAlwaysAllowedWithFlag, NULL);
21506 // Create an environment
21507 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
21509 v8::Handle<v8::Object> global0 = context0->Global();
21510 global0->Set(v8_str("object"), obj_template->NewInstance());
21512 v8::TryCatch try_catch(isolate);
21513 value = CompileRun("'use strong'; object.x");
21514 CHECK(!try_catch.HasCaught());
21515 CHECK(!access_was_called);
21516 CHECK_EQ(42, value->Int32Value());
21519 v8::TryCatch try_catch(isolate);
21520 value = CompileRun("'use strong'; object.foo");
21521 CHECK(try_catch.HasCaught());
21522 CHECK(!access_was_called);
21525 v8::TryCatch try_catch(isolate);
21526 value = CompileRun("'use strong'; object[10]");
21527 CHECK(try_catch.HasCaught());
21528 CHECK(!access_was_called);
21531 // Create an environment
21532 v8::Local<Context> context1 = Context::New(isolate);
21534 v8::Handle<v8::Object> global1 = context1->Global();
21535 global1->Set(v8_str("object"), obj_template->NewInstance());
21537 v8::TryCatch try_catch(isolate);
21538 value = CompileRun("'use strong'; object.x");
21539 CHECK(!try_catch.HasCaught());
21540 CHECK(access_was_called);
21541 CHECK_EQ(42, value->Int32Value());
21543 access_was_called = false;
21545 v8::TryCatch try_catch(isolate);
21546 value = CompileRun("'use strong'; object.foo");
21547 CHECK(try_catch.HasCaught());
21548 CHECK(access_was_called);
21550 access_was_called = false;
21552 v8::TryCatch try_catch(isolate);
21553 value = CompileRun("'use strong'; object[10]");
21554 CHECK(try_catch.HasCaught());
21555 CHECK(access_was_called);
21563 TEST(StrongModeAccessCheckBlocked) {
21564 i::FLAG_strong_mode = true;
21565 v8::Isolate* isolate = CcTest::isolate();
21566 v8::HandleScope handle_scope(isolate);
21567 v8::Handle<Value> value;
21568 access_was_called = false;
21570 v8::Handle<v8::ObjectTemplate> obj_template =
21571 v8::ObjectTemplate::New(isolate);
21573 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
21574 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlockedWithFlag, NULL);
21576 // Create an environment
21577 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
21579 v8::Handle<v8::Object> global0 = context0->Global();
21580 global0->Set(v8_str("object"), obj_template->NewInstance());
21582 v8::TryCatch try_catch(isolate);
21583 value = CompileRun("'use strong'; object.x");
21584 CHECK(!try_catch.HasCaught());
21585 CHECK(!access_was_called);
21586 CHECK_EQ(42, value->Int32Value());
21589 v8::TryCatch try_catch(isolate);
21590 value = CompileRun("'use strong'; object.foo");
21591 CHECK(try_catch.HasCaught());
21592 CHECK(!access_was_called);
21595 v8::TryCatch try_catch(isolate);
21596 value = CompileRun("'use strong'; object[10]");
21597 CHECK(try_catch.HasCaught());
21598 CHECK(!access_was_called);
21601 // Create an environment
21602 v8::Local<Context> context1 = Context::New(isolate);
21604 v8::Handle<v8::Object> global1 = context1->Global();
21605 global1->Set(v8_str("object"), obj_template->NewInstance());
21607 v8::TryCatch try_catch(isolate);
21608 value = CompileRun("'use strong'; object.x");
21609 CHECK(try_catch.HasCaught());
21610 CHECK(access_was_called);
21612 access_was_called = false;
21614 v8::TryCatch try_catch(isolate);
21615 value = CompileRun("'use strong'; object.foo");
21616 CHECK(try_catch.HasCaught());
21617 CHECK(access_was_called);
21619 access_was_called = false;
21621 v8::TryCatch try_catch(isolate);
21622 value = CompileRun("'use strong'; object[10]");
21623 CHECK(try_catch.HasCaught());
21624 CHECK(access_was_called);
21632 TEST(StrongModeArityCallFromApi) {
21633 i::FLAG_strong_mode = true;
21635 v8::Isolate* isolate = env->GetIsolate();
21636 v8::HandleScope scope(isolate);
21637 Local<Function> fun;
21639 v8::TryCatch try_catch(isolate);
21640 fun = Local<Function>::Cast(CompileRun(
21641 "function f(x) { 'use strong'; }"
21644 CHECK(!try_catch.HasCaught());
21648 v8::TryCatch try_catch(isolate);
21649 fun->Call(v8::Undefined(isolate), 0, nullptr);
21650 CHECK(try_catch.HasCaught());
21654 v8::TryCatch try_catch(isolate);
21655 v8::Handle<Value> args[] = {v8_num(42)};
21656 fun->Call(v8::Undefined(isolate), arraysize(args), args);
21657 CHECK(!try_catch.HasCaught());
21661 v8::TryCatch try_catch(isolate);
21662 v8::Handle<Value> args[] = {v8_num(42), v8_num(555)};
21663 fun->Call(v8::Undefined(isolate), arraysize(args), args);
21664 CHECK(!try_catch.HasCaught());
21669 TEST(StrongModeArityCallFromApi2) {
21670 i::FLAG_strong_mode = true;
21672 v8::Isolate* isolate = env->GetIsolate();
21673 v8::HandleScope scope(isolate);
21674 Local<Function> fun;
21676 v8::TryCatch try_catch(isolate);
21677 fun = Local<Function>::Cast(CompileRun(
21682 CHECK(!try_catch.HasCaught());
21686 v8::TryCatch try_catch(isolate);
21687 fun->Call(v8::Undefined(isolate), 0, nullptr);
21688 CHECK(try_catch.HasCaught());
21692 v8::TryCatch try_catch(isolate);
21693 v8::Handle<Value> args[] = {v8_num(42)};
21694 fun->Call(v8::Undefined(isolate), arraysize(args), args);
21695 CHECK(!try_catch.HasCaught());
21699 v8::TryCatch try_catch(isolate);
21700 v8::Handle<Value> args[] = {v8_num(42), v8_num(555)};
21701 fun->Call(v8::Undefined(isolate), arraysize(args), args);
21702 CHECK(!try_catch.HasCaught());
21707 TEST(StrongObjectDelete) {
21708 i::FLAG_strong_mode = true;
21710 v8::Isolate* isolate = env->GetIsolate();
21711 v8::HandleScope scope(isolate);
21714 v8::TryCatch try_catch;
21715 obj = Local<Object>::Cast(CompileRun(
21718 CHECK(!try_catch.HasCaught());
21720 obj->ForceSet(v8_str("foo"), v8_num(1), v8::None);
21721 obj->ForceSet(v8_str("2"), v8_num(1), v8::None);
21722 CHECK(obj->HasOwnProperty(v8_str("foo")));
21723 CHECK(obj->HasOwnProperty(v8_str("2")));
21724 CHECK(!obj->Delete(v8_str("foo")));
21725 CHECK(!obj->Delete(2));
21729 static void ExtrasExportsTestRuntimeFunction(
21730 const v8::FunctionCallbackInfo<v8::Value>& args) {
21731 CHECK_EQ(3, args[0]->Int32Value());
21732 args.GetReturnValue().Set(v8_num(7));
21736 TEST(ExtrasExportsObject) {
21737 v8::Isolate* isolate = CcTest::isolate();
21738 v8::HandleScope handle_scope(isolate);
21741 // standalone.gypi ensures we include the test-extra.js file, which should
21742 // export the tested functions.
21743 v8::Local<v8::Object> exports = env->GetExtrasExportsObject();
21746 exports->Get(v8_str("testExtraShouldReturnFive")).As<v8::Function>();
21747 auto undefined = v8::Undefined(isolate);
21748 auto result = func->Call(undefined, 0, {}).As<v8::Number>();
21749 CHECK_EQ(5, result->Int32Value());
21751 v8::Handle<v8::FunctionTemplate> runtimeFunction =
21752 v8::FunctionTemplate::New(isolate, ExtrasExportsTestRuntimeFunction);
21753 exports->Set(v8_str("runtime"), runtimeFunction->GetFunction());
21755 exports->Get(v8_str("testExtraShouldCallToRuntime")).As<v8::Function>();
21756 result = func->Call(undefined, 0, {}).As<v8::Number>();
21757 CHECK_EQ(7, result->Int32Value());
21762 v8::Isolate* isolate = CcTest::isolate();
21763 v8::HandleScope handle_scope(isolate);
21766 v8::Local<v8::Map> map = v8::Map::New(isolate);
21767 CHECK(map->IsObject());
21768 CHECK(map->IsMap());
21769 CHECK(map->GetPrototype()->StrictEquals(CompileRun("Map.prototype")));
21770 CHECK_EQ(0U, map->Size());
21772 v8::Local<v8::Value> val = CompileRun("new Map([[1, 2], [3, 4]])");
21773 CHECK(val->IsMap());
21774 map = v8::Local<v8::Map>::Cast(val);
21775 CHECK_EQ(2U, map->Size());
21777 v8::Local<v8::Array> contents = map->AsArray();
21778 CHECK_EQ(4U, contents->Length());
21779 CHECK_EQ(1, contents->Get(0).As<v8::Int32>()->Value());
21780 CHECK_EQ(2, contents->Get(1).As<v8::Int32>()->Value());
21781 CHECK_EQ(3, contents->Get(2).As<v8::Int32>()->Value());
21782 CHECK_EQ(4, contents->Get(3).As<v8::Int32>()->Value());
21784 map = v8::Map::FromArray(env.local(), contents).ToLocalChecked();
21785 CHECK_EQ(2U, map->Size());
21787 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
21788 CHECK(map->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
21790 CHECK(!map->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
21791 CHECK(!map->Has(env.local(), map).FromJust());
21793 CHECK_EQ(2, map->Get(env.local(), v8::Integer::New(isolate, 1))
21796 CHECK_EQ(4, map->Get(env.local(), v8::Integer::New(isolate, 3))
21800 CHECK(map->Get(env.local(), v8::Integer::New(isolate, 42))
21804 CHECK(!map->Set(env.local(), map, map).IsEmpty());
21805 CHECK_EQ(3U, map->Size());
21806 CHECK(map->Has(env.local(), map).FromJust());
21808 CHECK(map->Delete(env.local(), map).FromJust());
21809 CHECK_EQ(2U, map->Size());
21810 CHECK(!map->Has(env.local(), map).FromJust());
21811 CHECK(!map->Delete(env.local(), map).FromJust());
21814 CHECK_EQ(0U, map->Size());
21818 TEST(MapFromArrayOddLength) {
21819 v8::Isolate* isolate = CcTest::isolate();
21820 v8::HandleScope handle_scope(isolate);
21822 // Odd lengths result in a null MaybeLocal.
21823 Local<v8::Array> contents = v8::Array::New(isolate, 41);
21824 CHECK(v8::Map::FromArray(env.local(), contents).IsEmpty());
21829 v8::Isolate* isolate = CcTest::isolate();
21830 v8::HandleScope handle_scope(isolate);
21833 v8::Local<v8::Set> set = v8::Set::New(isolate);
21834 CHECK(set->IsObject());
21835 CHECK(set->IsSet());
21836 CHECK(set->GetPrototype()->StrictEquals(CompileRun("Set.prototype")));
21837 CHECK_EQ(0U, set->Size());
21839 v8::Local<v8::Value> val = CompileRun("new Set([1, 2])");
21840 CHECK(val->IsSet());
21841 set = v8::Local<v8::Set>::Cast(val);
21842 CHECK_EQ(2U, set->Size());
21844 v8::Local<v8::Array> keys = set->AsArray();
21845 CHECK_EQ(2U, keys->Length());
21846 CHECK_EQ(1, keys->Get(0).As<v8::Int32>()->Value());
21847 CHECK_EQ(2, keys->Get(1).As<v8::Int32>()->Value());
21849 set = v8::Set::FromArray(env.local(), keys).ToLocalChecked();
21850 CHECK_EQ(2U, set->Size());
21852 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 1)).FromJust());
21853 CHECK(set->Has(env.local(), v8::Integer::New(isolate, 2)).FromJust());
21855 CHECK(!set->Has(env.local(), v8::Integer::New(isolate, 3)).FromJust());
21856 CHECK(!set->Has(env.local(), set).FromJust());
21858 CHECK(!set->Add(env.local(), set).IsEmpty());
21859 CHECK_EQ(3U, set->Size());
21860 CHECK(set->Has(env.local(), set).FromJust());
21862 CHECK(set->Delete(env.local(), set).FromJust());
21863 CHECK_EQ(2U, set->Size());
21864 CHECK(!set->Has(env.local(), set).FromJust());
21865 CHECK(!set->Delete(env.local(), set).FromJust());
21868 CHECK_EQ(0U, set->Size());
21872 TEST(CompatibleReceiverCheckOnCachedICHandler) {
21873 v8::Isolate* isolate = CcTest::isolate();
21874 v8::HandleScope scope(isolate);
21875 v8::Local<v8::FunctionTemplate> parent = FunctionTemplate::New(isolate);
21876 v8::Local<v8::Signature> signature = v8::Signature::New(isolate, parent);
21878 v8::FunctionTemplate::New(isolate, Returns42, Local<Value>(), signature);
21879 parent->PrototypeTemplate()->SetAccessorProperty(v8_str("age"), returns_42);
21880 v8::Local<v8::FunctionTemplate> child = v8::FunctionTemplate::New(isolate);
21881 child->Inherit(parent);
21883 env->Global()->Set(v8_str("Child"), child->GetFunction());
21885 // Make sure there's a compiled stub for "Child.prototype.age" in the cache.
21887 "var real = new Child();\n"
21888 "for (var i = 0; i < 3; ++i) {\n"
21892 // Check that the cached stub is never used.
21894 "var fake = Object.create(Child.prototype);\n"
21895 "var result = 0;\n"
21896 "function test(d) {\n"
21897 " if (d == 3) return;\n"
21911 static int nb_uncaught_exception_callback_calls = 0;
21914 bool NoAbortOnUncaughtException(v8::Isolate* isolate) {
21915 ++nb_uncaught_exception_callback_calls;
21920 TEST(AbortOnUncaughtExceptionNoAbort) {
21921 v8::Isolate* isolate = CcTest::isolate();
21922 v8::HandleScope handle_scope(isolate);
21923 v8::Handle<v8::ObjectTemplate> global_template =
21924 v8::ObjectTemplate::New(isolate);
21925 LocalContext env(NULL, global_template);
21927 i::FLAG_abort_on_uncaught_exception = true;
21928 isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException);
21930 CompileRun("function boom() { throw new Error(\"boom\") }");
21932 v8::Local<v8::Object> global_object = env->Global();
21933 v8::Local<v8::Function> foo =
21934 v8::Local<v8::Function>::Cast(global_object->Get(v8_str("boom")));
21936 foo->Call(global_object, 0, NULL);
21938 CHECK_EQ(1, nb_uncaught_exception_callback_calls);