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/execution.h"
45 #include "src/objects.h"
46 #include "src/parser.h"
47 #include "src/smart-pointers.h"
48 #include "src/unicode-inl.h"
49 #include "src/utils.h"
50 #include "src/vm-state.h"
52 static const bool kLogThreading = false;
55 using ::v8::BooleanObject;
57 using ::v8::Extension;
59 using ::v8::FunctionTemplate;
61 using ::v8::HandleScope;
65 using ::v8::MessageCallback;
69 using ::v8::ObjectTemplate;
70 using ::v8::Persistent;
71 using ::v8::PropertyAttribute;
73 using ::v8::StackTrace;
77 using ::v8::Undefined;
83 #define THREADED_PROFILED_TEST(Name) \
84 static void Test##Name(); \
85 TEST(Name##WithProfiler) { \
86 RunWithProfiler(&Test##Name); \
91 void RunWithProfiler(void (*test)()) {
93 v8::HandleScope scope(env->GetIsolate());
94 v8::Local<v8::String> profile_name =
95 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
96 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
98 cpu_profiler->StartProfiling(profile_name);
100 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
104 static int signature_callback_count;
105 static Local<Value> signature_expected_receiver;
106 static void IncrementingSignatureCallback(
107 const v8::FunctionCallbackInfo<v8::Value>& args) {
108 ApiTestFuzzer::Fuzz();
109 signature_callback_count++;
110 CHECK(signature_expected_receiver->Equals(args.Holder()));
111 CHECK(signature_expected_receiver->Equals(args.This()));
112 v8::Handle<v8::Array> result =
113 v8::Array::New(args.GetIsolate(), args.Length());
114 for (int i = 0; i < args.Length(); i++)
115 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
116 args.GetReturnValue().Set(result);
120 static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
121 info.GetReturnValue().Set(42);
125 // Tests that call v8::V8::Dispose() cannot be threaded.
126 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
127 CHECK(v8::V8::Initialize());
128 CHECK(v8::V8::Dispose());
132 // Tests that call v8::V8::Dispose() cannot be threaded.
133 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
134 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
135 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
136 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
137 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
138 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142 THREADED_TEST(Handles) {
143 v8::HandleScope scope(CcTest::isolate());
144 Local<Context> local_env;
147 local_env = env.local();
150 // Local context should still be live.
151 CHECK(!local_env.IsEmpty());
154 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
155 CHECK(!undef.IsEmpty());
156 CHECK(undef->IsUndefined());
158 const char* source = "1 + 2 + 3";
159 Local<Script> script = v8_compile(source);
160 CHECK_EQ(6, script->Run()->Int32Value());
166 THREADED_TEST(IsolateOfContext) {
167 v8::HandleScope scope(CcTest::isolate());
168 v8::Handle<Context> env = Context::New(CcTest::isolate());
170 CHECK(!env->GetIsolate()->InContext());
171 CHECK(env->GetIsolate() == CcTest::isolate());
173 CHECK(env->GetIsolate()->InContext());
174 CHECK(env->GetIsolate() == CcTest::isolate());
176 CHECK(!env->GetIsolate()->InContext());
177 CHECK(env->GetIsolate() == CcTest::isolate());
181 static void TestSignature(const char* loop_js, Local<Value> receiver,
182 v8::Isolate* isolate) {
183 i::ScopedVector<char> source(200);
185 "for (var i = 0; i < 10; i++) {"
189 signature_callback_count = 0;
190 signature_expected_receiver = receiver;
191 bool expected_to_throw = receiver.IsEmpty();
192 v8::TryCatch try_catch;
193 CompileRun(source.start());
194 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
195 if (!expected_to_throw) {
196 CHECK_EQ(10, signature_callback_count);
198 CHECK(v8_str("TypeError: Illegal invocation")
199 ->Equals(try_catch.Exception()->ToString(isolate)));
204 THREADED_TEST(ReceiverSignature) {
206 v8::Isolate* isolate = env->GetIsolate();
207 v8::HandleScope scope(isolate);
209 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
210 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
211 v8::Handle<v8::FunctionTemplate> callback_sig =
212 v8::FunctionTemplate::New(
213 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
214 v8::Handle<v8::FunctionTemplate> callback =
215 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
216 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
217 sub_fun->Inherit(fun);
218 v8::Handle<v8::FunctionTemplate> unrel_fun =
219 v8::FunctionTemplate::New(isolate);
220 // Install properties.
221 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
222 fun_proto->Set(v8_str("prop_sig"), callback_sig);
223 fun_proto->Set(v8_str("prop"), callback);
224 fun_proto->SetAccessorProperty(
225 v8_str("accessor_sig"), callback_sig, callback_sig);
226 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
227 // Instantiate templates.
228 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
229 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
230 // Setup global variables.
231 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
232 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
233 env->Global()->Set(v8_str("fun_instance"), fun_instance);
234 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
236 "var accessor_sig_key = 'accessor_sig';"
237 "var accessor_key = 'accessor';"
238 "var prop_sig_key = 'prop_sig';"
239 "var prop_key = 'prop';"
241 "function copy_props(obj) {"
242 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
243 " var source = Fun.prototype;"
244 " for (var i in keys) {"
245 " var key = keys[i];"
246 " var desc = Object.getOwnPropertyDescriptor(source, key);"
247 " Object.defineProperty(obj, key, desc);"
253 "var unrel = new UnrelFun();"
254 "copy_props(unrel);");
255 // Test with and without ICs
256 const char* test_objects[] = {
257 "fun_instance", "sub_fun_instance", "obj", "unrel" };
258 unsigned bad_signature_start_offset = 2;
259 for (unsigned i = 0; i < arraysize(test_objects); i++) {
260 i::ScopedVector<char> source(200);
262 source, "var test_object = %s; test_object", test_objects[i]);
263 Local<Value> test_object = CompileRun(source.start());
264 TestSignature("test_object.prop();", test_object, isolate);
265 TestSignature("test_object.accessor;", test_object, isolate);
266 TestSignature("test_object[accessor_key];", test_object, isolate);
267 TestSignature("test_object.accessor = 1;", test_object, isolate);
268 TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
269 if (i >= bad_signature_start_offset) test_object = Local<Value>();
270 TestSignature("test_object.prop_sig();", test_object, isolate);
271 TestSignature("test_object.accessor_sig;", test_object, isolate);
272 TestSignature("test_object[accessor_sig_key];", test_object, isolate);
273 TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
274 TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
279 THREADED_TEST(HulIgennem) {
281 v8::Isolate* isolate = env->GetIsolate();
282 v8::HandleScope scope(isolate);
283 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
284 Local<String> undef_str = undef->ToString(isolate);
285 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
286 undef_str->WriteUtf8(value);
287 CHECK_EQ(0, strcmp(value, "undefined"));
288 i::DeleteArray(value);
292 THREADED_TEST(Access) {
294 v8::Isolate* isolate = env->GetIsolate();
295 v8::HandleScope scope(isolate);
296 Local<v8::Object> obj = v8::Object::New(isolate);
297 Local<Value> foo_before = obj->Get(v8_str("foo"));
298 CHECK(foo_before->IsUndefined());
299 Local<String> bar_str = v8_str("bar");
300 obj->Set(v8_str("foo"), bar_str);
301 Local<Value> foo_after = obj->Get(v8_str("foo"));
302 CHECK(!foo_after->IsUndefined());
303 CHECK(foo_after->IsString());
304 CHECK(bar_str->Equals(foo_after));
308 THREADED_TEST(AccessElement) {
310 v8::HandleScope scope(env->GetIsolate());
311 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
312 Local<Value> before = obj->Get(1);
313 CHECK(before->IsUndefined());
314 Local<String> bar_str = v8_str("bar");
315 obj->Set(1, bar_str);
316 Local<Value> after = obj->Get(1);
317 CHECK(!after->IsUndefined());
318 CHECK(after->IsString());
319 CHECK(bar_str->Equals(after));
321 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
322 CHECK(v8_str("a")->Equals(value->Get(0)));
323 CHECK(v8_str("b")->Equals(value->Get(1)));
327 THREADED_TEST(Script) {
329 v8::HandleScope scope(env->GetIsolate());
330 const char* source = "1 + 2 + 3";
331 Local<Script> script = v8_compile(source);
332 CHECK_EQ(6, script->Run()->Int32Value());
336 class TestResource: public String::ExternalStringResource {
338 explicit TestResource(uint16_t* data, int* counter = NULL,
339 bool owning_data = true)
340 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
341 while (data[length_]) ++length_;
345 if (owning_data_) i::DeleteArray(data_);
346 if (counter_ != NULL) ++*counter_;
349 const uint16_t* data() const {
353 size_t length() const {
365 class TestOneByteResource : public String::ExternalOneByteStringResource {
367 explicit TestOneByteResource(const char* data, int* counter = NULL,
370 data_(data + offset),
371 length_(strlen(data) - offset),
374 ~TestOneByteResource() {
375 i::DeleteArray(orig_data_);
376 if (counter_ != NULL) ++*counter_;
379 const char* data() const {
383 size_t length() const {
388 const char* orig_data_;
395 THREADED_TEST(ScriptUsingStringResource) {
396 int dispose_count = 0;
397 const char* c_source = "1 + 2 * 3";
398 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
401 v8::HandleScope scope(env->GetIsolate());
402 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
403 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
404 Local<Script> script = v8_compile(source);
405 Local<Value> value = script->Run();
406 CHECK(value->IsNumber());
407 CHECK_EQ(7, value->Int32Value());
408 CHECK(source->IsExternal());
410 static_cast<TestResource*>(source->GetExternalStringResource()));
411 String::Encoding encoding = String::UNKNOWN_ENCODING;
412 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
413 source->GetExternalStringResourceBase(&encoding));
414 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
415 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
416 CHECK_EQ(0, dispose_count);
418 CcTest::i_isolate()->compilation_cache()->Clear();
419 CcTest::heap()->CollectAllAvailableGarbage();
420 CHECK_EQ(1, dispose_count);
424 THREADED_TEST(ScriptUsingOneByteStringResource) {
425 int dispose_count = 0;
426 const char* c_source = "1 + 2 * 3";
429 v8::HandleScope scope(env->GetIsolate());
430 TestOneByteResource* resource =
431 new TestOneByteResource(i::StrDup(c_source), &dispose_count);
432 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
433 CHECK(source->IsExternalOneByte());
434 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
435 source->GetExternalOneByteStringResource());
436 String::Encoding encoding = String::UNKNOWN_ENCODING;
437 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
438 source->GetExternalStringResourceBase(&encoding));
439 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
440 Local<Script> script = v8_compile(source);
441 Local<Value> value = script->Run();
442 CHECK(value->IsNumber());
443 CHECK_EQ(7, value->Int32Value());
444 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
445 CHECK_EQ(0, dispose_count);
447 CcTest::i_isolate()->compilation_cache()->Clear();
448 CcTest::heap()->CollectAllAvailableGarbage();
449 CHECK_EQ(1, dispose_count);
453 THREADED_TEST(ScriptMakingExternalString) {
454 int dispose_count = 0;
455 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
458 v8::HandleScope scope(env->GetIsolate());
459 Local<String> source =
460 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
461 // Trigger GCs so that the newly allocated string moves to old gen.
462 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
463 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
464 CHECK_EQ(source->IsExternal(), false);
465 CHECK_EQ(source->IsExternalOneByte(), false);
466 String::Encoding encoding = String::UNKNOWN_ENCODING;
467 CHECK(!source->GetExternalStringResourceBase(&encoding));
468 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
469 bool success = source->MakeExternal(new TestResource(two_byte_source,
472 Local<Script> script = v8_compile(source);
473 Local<Value> value = script->Run();
474 CHECK(value->IsNumber());
475 CHECK_EQ(7, value->Int32Value());
476 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
477 CHECK_EQ(0, dispose_count);
479 CcTest::i_isolate()->compilation_cache()->Clear();
480 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
481 CHECK_EQ(1, dispose_count);
485 THREADED_TEST(ScriptMakingExternalOneByteString) {
486 int dispose_count = 0;
487 const char* c_source = "1 + 2 * 3";
490 v8::HandleScope scope(env->GetIsolate());
491 Local<String> source = v8_str(c_source);
492 // Trigger GCs so that the newly allocated string moves to old gen.
493 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
494 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
495 bool success = source->MakeExternal(
496 new TestOneByteResource(i::StrDup(c_source), &dispose_count));
498 Local<Script> script = v8_compile(source);
499 Local<Value> value = script->Run();
500 CHECK(value->IsNumber());
501 CHECK_EQ(7, value->Int32Value());
502 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
503 CHECK_EQ(0, dispose_count);
505 CcTest::i_isolate()->compilation_cache()->Clear();
506 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
507 CHECK_EQ(1, dispose_count);
511 TEST(MakingExternalStringConditions) {
513 v8::HandleScope scope(env->GetIsolate());
515 // Free some space in the new space so that we can check freshness.
516 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
517 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
519 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
520 Local<String> small_string =
521 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
522 i::DeleteArray(two_byte_string);
524 // We should refuse to externalize newly created small string.
525 CHECK(!small_string->CanMakeExternal());
526 // Trigger GCs so that the newly allocated string moves to old gen.
527 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
528 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
529 // Old space strings should be accepted.
530 CHECK(small_string->CanMakeExternal());
532 two_byte_string = AsciiToTwoByteString("small string 2");
533 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
534 i::DeleteArray(two_byte_string);
536 // We should refuse externalizing newly created small string.
537 CHECK(!small_string->CanMakeExternal());
538 for (int i = 0; i < 100; i++) {
539 String::Value value(small_string);
541 // Frequently used strings should be accepted.
542 CHECK(small_string->CanMakeExternal());
544 const int buf_size = 10 * 1024;
545 char* buf = i::NewArray<char>(buf_size);
546 memset(buf, 'a', buf_size);
547 buf[buf_size - 1] = '\0';
549 two_byte_string = AsciiToTwoByteString(buf);
550 Local<String> large_string =
551 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
553 i::DeleteArray(two_byte_string);
554 // Large strings should be immediately accepted.
555 CHECK(large_string->CanMakeExternal());
559 TEST(MakingExternalOneByteStringConditions) {
561 v8::HandleScope scope(env->GetIsolate());
563 // Free some space in the new space so that we can check freshness.
564 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
565 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
567 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
568 // We should refuse to externalize newly created small string.
569 CHECK(!small_string->CanMakeExternal());
570 // Trigger GCs so that the newly allocated string moves to old gen.
571 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
572 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
573 // Old space strings should be accepted.
574 CHECK(small_string->CanMakeExternal());
576 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
577 // We should refuse externalizing newly created small string.
578 CHECK(!small_string->CanMakeExternal());
579 for (int i = 0; i < 100; i++) {
580 String::Value value(small_string);
582 // Frequently used strings should be accepted.
583 CHECK(small_string->CanMakeExternal());
585 const int buf_size = 10 * 1024;
586 char* buf = i::NewArray<char>(buf_size);
587 memset(buf, 'a', buf_size);
588 buf[buf_size - 1] = '\0';
589 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
591 // Large strings should be immediately accepted.
592 CHECK(large_string->CanMakeExternal());
596 TEST(MakingExternalUnalignedOneByteString) {
598 v8::HandleScope scope(env->GetIsolate());
600 CompileRun("function cons(a, b) { return a + b; }"
601 "function slice(a) { return a.substring(1); }");
602 // Create a cons string that will land in old pointer space.
603 Local<String> cons = Local<String>::Cast(CompileRun(
604 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
605 // Create a sliced string that will land in old pointer space.
606 Local<String> slice = Local<String>::Cast(CompileRun(
607 "slice('abcdefghijklmnopqrstuvwxyz');"));
609 // Trigger GCs so that the newly allocated string moves to old gen.
610 SimulateFullSpace(CcTest::heap()->old_pointer_space());
611 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
612 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
614 // Turn into external string with unaligned resource data.
615 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
617 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
619 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
621 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
624 // Trigger GCs and force evacuation.
625 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
626 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
630 THREADED_TEST(UsingExternalString) {
631 i::Factory* factory = CcTest::i_isolate()->factory();
633 v8::HandleScope scope(CcTest::isolate());
634 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
635 Local<String> string = String::NewExternal(
636 CcTest::isolate(), new TestResource(two_byte_string));
637 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
638 // Trigger GCs so that the newly allocated string moves to old gen.
639 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
640 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
641 i::Handle<i::String> isymbol =
642 factory->InternalizeString(istring);
643 CHECK(isymbol->IsInternalizedString());
645 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
646 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
650 THREADED_TEST(UsingExternalOneByteString) {
651 i::Factory* factory = CcTest::i_isolate()->factory();
653 v8::HandleScope scope(CcTest::isolate());
654 const char* one_byte_string = "test string";
655 Local<String> string = String::NewExternal(
656 CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
657 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
658 // Trigger GCs so that the newly allocated string moves to old gen.
659 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
660 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
661 i::Handle<i::String> isymbol =
662 factory->InternalizeString(istring);
663 CHECK(isymbol->IsInternalizedString());
665 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
666 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
670 class RandomLengthResource : public v8::String::ExternalStringResource {
672 explicit RandomLengthResource(int length) : length_(length) {}
673 virtual const uint16_t* data() const { return string_; }
674 virtual size_t length() const { return length_; }
677 uint16_t string_[10];
682 class RandomLengthOneByteResource
683 : public v8::String::ExternalOneByteStringResource {
685 explicit RandomLengthOneByteResource(int length) : length_(length) {}
686 virtual const char* data() const { return string_; }
687 virtual size_t length() const { return length_; }
695 THREADED_TEST(NewExternalForVeryLongString) {
696 auto isolate = CcTest::isolate();
698 v8::HandleScope scope(isolate);
699 v8::TryCatch try_catch;
700 RandomLengthOneByteResource r(1 << 30);
701 v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
702 CHECK(str.IsEmpty());
703 CHECK(!try_catch.HasCaught());
707 v8::HandleScope scope(isolate);
708 v8::TryCatch try_catch;
709 RandomLengthResource r(1 << 30);
710 v8::Local<v8::String> str = v8::String::NewExternal(isolate, &r);
711 CHECK(str.IsEmpty());
712 CHECK(!try_catch.HasCaught());
717 THREADED_TEST(ScavengeExternalString) {
718 i::FLAG_stress_compaction = false;
719 i::FLAG_gc_global = false;
720 int dispose_count = 0;
721 bool in_new_space = false;
723 v8::HandleScope scope(CcTest::isolate());
724 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
725 Local<String> string = String::NewExternal(
726 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
727 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
728 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
729 in_new_space = CcTest::heap()->InNewSpace(*istring);
730 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
731 CHECK_EQ(0, dispose_count);
733 CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE
734 : i::OLD_DATA_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_data_space()->Contains(*istring));
754 CHECK_EQ(0, dispose_count);
756 CcTest::heap()->CollectGarbage(in_new_space ? i::NEW_SPACE
757 : i::OLD_DATA_SPACE);
758 CHECK_EQ(1, dispose_count);
762 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
764 // Only used by non-threaded tests, so it can use static fields.
765 static int dispose_calls;
766 static int dispose_count;
768 TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
769 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
773 if (dispose_) delete this;
780 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
781 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
784 TEST(ExternalStringWithDisposeHandling) {
785 const char* c_source = "1 + 2 * 3";
787 // Use a stack allocated external string resource allocated object.
788 TestOneByteResourceWithDisposeControl::dispose_count = 0;
789 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
790 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
793 v8::HandleScope scope(env->GetIsolate());
794 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
795 Local<Script> script = v8_compile(source);
796 Local<Value> value = script->Run();
797 CHECK(value->IsNumber());
798 CHECK_EQ(7, value->Int32Value());
799 CcTest::heap()->CollectAllAvailableGarbage();
800 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
802 CcTest::i_isolate()->compilation_cache()->Clear();
803 CcTest::heap()->CollectAllAvailableGarbage();
804 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
805 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
807 // Use a heap allocated external string resource allocated object.
808 TestOneByteResourceWithDisposeControl::dispose_count = 0;
809 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
810 TestOneByteResource* res_heap =
811 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
814 v8::HandleScope scope(env->GetIsolate());
815 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
816 Local<Script> script = v8_compile(source);
817 Local<Value> value = script->Run();
818 CHECK(value->IsNumber());
819 CHECK_EQ(7, value->Int32Value());
820 CcTest::heap()->CollectAllAvailableGarbage();
821 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
823 CcTest::i_isolate()->compilation_cache()->Clear();
824 CcTest::heap()->CollectAllAvailableGarbage();
825 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
826 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
830 THREADED_TEST(StringConcat) {
833 v8::HandleScope scope(env->GetIsolate());
834 const char* one_byte_string_1 = "function a_times_t";
835 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
836 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
837 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
838 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
839 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
840 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
841 Local<String> left = v8_str(one_byte_string_1);
843 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
844 Local<String> right =
845 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
846 i::DeleteArray(two_byte_source);
848 Local<String> source = String::Concat(left, right);
849 right = String::NewExternal(
851 new TestOneByteResource(i::StrDup(one_byte_extern_1)));
852 source = String::Concat(source, right);
853 right = String::NewExternal(
855 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
856 source = String::Concat(source, right);
857 right = v8_str(one_byte_string_2);
858 source = String::Concat(source, right);
860 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
861 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
862 i::DeleteArray(two_byte_source);
864 source = String::Concat(source, right);
865 right = String::NewExternal(
867 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
868 source = String::Concat(source, right);
869 Local<Script> script = v8_compile(source);
870 Local<Value> value = script->Run();
871 CHECK(value->IsNumber());
872 CHECK_EQ(68, value->Int32Value());
874 CcTest::i_isolate()->compilation_cache()->Clear();
875 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
876 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
880 THREADED_TEST(GlobalProperties) {
882 v8::HandleScope scope(env->GetIsolate());
883 v8::Handle<v8::Object> global = env->Global();
884 global->Set(v8_str("pi"), v8_num(3.1415926));
885 Local<Value> pi = global->Get(v8_str("pi"));
886 CHECK_EQ(3.1415926, pi->NumberValue());
890 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
891 i::Address callback) {
892 ApiTestFuzzer::Fuzz();
893 CheckReturnValue(info, callback);
894 info.GetReturnValue().Set(v8_str("bad value"));
895 info.GetReturnValue().Set(v8_num(102));
899 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
900 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
904 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
905 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
908 static void construct_callback(
909 const v8::FunctionCallbackInfo<Value>& info) {
910 ApiTestFuzzer::Fuzz();
911 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
912 info.This()->Set(v8_str("x"), v8_num(1));
913 info.This()->Set(v8_str("y"), v8_num(2));
914 info.GetReturnValue().Set(v8_str("bad value"));
915 info.GetReturnValue().Set(info.This());
919 static void Return239Callback(
920 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
921 ApiTestFuzzer::Fuzz();
922 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
923 info.GetReturnValue().Set(v8_str("bad value"));
924 info.GetReturnValue().Set(v8_num(239));
928 template<typename Handler>
929 static void TestFunctionTemplateInitializer(Handler handler,
931 // Test constructor calls.
934 v8::Isolate* isolate = env->GetIsolate();
935 v8::HandleScope scope(isolate);
937 Local<v8::FunctionTemplate> fun_templ =
938 v8::FunctionTemplate::New(isolate, handler);
939 Local<Function> fun = fun_templ->GetFunction();
940 env->Global()->Set(v8_str("obj"), fun);
941 Local<Script> script = v8_compile("obj()");
942 for (int i = 0; i < 30; i++) {
943 CHECK_EQ(102, script->Run()->Int32Value());
946 // Use SetCallHandler to initialize a function template, should work like
950 v8::Isolate* isolate = env->GetIsolate();
951 v8::HandleScope scope(isolate);
953 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
954 fun_templ->SetCallHandler(handler_2);
955 Local<Function> fun = fun_templ->GetFunction();
956 env->Global()->Set(v8_str("obj"), fun);
957 Local<Script> script = v8_compile("obj()");
958 for (int i = 0; i < 30; i++) {
959 CHECK_EQ(102, script->Run()->Int32Value());
965 template<typename Constructor, typename Accessor>
966 static void TestFunctionTemplateAccessor(Constructor constructor,
969 v8::HandleScope scope(env->GetIsolate());
971 Local<v8::FunctionTemplate> fun_templ =
972 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
973 fun_templ->SetClassName(v8_str("funky"));
974 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
975 Local<Function> fun = fun_templ->GetFunction();
976 env->Global()->Set(v8_str("obj"), fun);
977 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
978 CHECK(v8_str("[object funky]")->Equals(result));
979 CompileRun("var obj_instance = new obj();");
980 Local<Script> script;
981 script = v8_compile("obj_instance.x");
982 for (int i = 0; i < 30; i++) {
983 CHECK_EQ(1, script->Run()->Int32Value());
985 script = v8_compile("obj_instance.m");
986 for (int i = 0; i < 30; i++) {
987 CHECK_EQ(239, script->Run()->Int32Value());
992 THREADED_PROFILED_TEST(FunctionTemplate) {
993 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
994 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
998 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
999 ApiTestFuzzer::Fuzz();
1000 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1001 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1005 template<typename Callback>
1006 static void TestSimpleCallback(Callback callback) {
1008 v8::Isolate* isolate = env->GetIsolate();
1009 v8::HandleScope scope(isolate);
1011 v8::Handle<v8::ObjectTemplate> object_template =
1012 v8::ObjectTemplate::New(isolate);
1013 object_template->Set(isolate, "callback",
1014 v8::FunctionTemplate::New(isolate, callback));
1015 v8::Local<v8::Object> object = object_template->NewInstance();
1016 (*env)->Global()->Set(v8_str("callback_object"), object);
1017 v8::Handle<v8::Script> script;
1018 script = v8_compile("callback_object.callback(17)");
1019 for (int i = 0; i < 30; i++) {
1020 CHECK_EQ(51424, script->Run()->Int32Value());
1022 script = v8_compile("callback_object.callback(17, 24)");
1023 for (int i = 0; i < 30; i++) {
1024 CHECK_EQ(51425, script->Run()->Int32Value());
1029 THREADED_PROFILED_TEST(SimpleCallback) {
1030 TestSimpleCallback(SimpleCallback);
1034 template<typename T>
1035 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1037 // constant return values
1038 static int32_t fast_return_value_int32 = 471;
1039 static uint32_t fast_return_value_uint32 = 571;
1040 static const double kFastReturnValueDouble = 2.7;
1041 // variable return values
1042 static bool fast_return_value_bool = false;
1043 enum ReturnValueOddball {
1045 kUndefinedReturnValue,
1046 kEmptyStringReturnValue
1048 static ReturnValueOddball fast_return_value_void;
1049 static bool fast_return_value_object_is_empty = false;
1051 // Helper function to avoid compiler error: insufficient contextual information
1052 // to determine type when applying FUNCTION_ADDR to a template function.
1053 static i::Address address_of(v8::FunctionCallback callback) {
1054 return FUNCTION_ADDR(callback);
1058 void FastReturnValueCallback<int32_t>(
1059 const v8::FunctionCallbackInfo<v8::Value>& info) {
1060 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1061 info.GetReturnValue().Set(fast_return_value_int32);
1065 void FastReturnValueCallback<uint32_t>(
1066 const v8::FunctionCallbackInfo<v8::Value>& info) {
1067 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1068 info.GetReturnValue().Set(fast_return_value_uint32);
1072 void FastReturnValueCallback<double>(
1073 const v8::FunctionCallbackInfo<v8::Value>& info) {
1074 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1075 info.GetReturnValue().Set(kFastReturnValueDouble);
1079 void FastReturnValueCallback<bool>(
1080 const v8::FunctionCallbackInfo<v8::Value>& info) {
1081 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1082 info.GetReturnValue().Set(fast_return_value_bool);
1086 void FastReturnValueCallback<void>(
1087 const v8::FunctionCallbackInfo<v8::Value>& info) {
1088 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1089 switch (fast_return_value_void) {
1090 case kNullReturnValue:
1091 info.GetReturnValue().SetNull();
1093 case kUndefinedReturnValue:
1094 info.GetReturnValue().SetUndefined();
1096 case kEmptyStringReturnValue:
1097 info.GetReturnValue().SetEmptyString();
1103 void FastReturnValueCallback<Object>(
1104 const v8::FunctionCallbackInfo<v8::Value>& info) {
1105 v8::Handle<v8::Object> object;
1106 if (!fast_return_value_object_is_empty) {
1107 object = Object::New(info.GetIsolate());
1109 info.GetReturnValue().Set(object);
1112 template<typename T>
1113 Handle<Value> TestFastReturnValues() {
1115 v8::Isolate* isolate = env->GetIsolate();
1116 v8::EscapableHandleScope scope(isolate);
1117 v8::Handle<v8::ObjectTemplate> object_template =
1118 v8::ObjectTemplate::New(isolate);
1119 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1120 object_template->Set(isolate, "callback",
1121 v8::FunctionTemplate::New(isolate, callback));
1122 v8::Local<v8::Object> object = object_template->NewInstance();
1123 (*env)->Global()->Set(v8_str("callback_object"), object);
1124 return scope.Escape(CompileRun("callback_object.callback()"));
1128 THREADED_PROFILED_TEST(FastReturnValues) {
1130 v8::Isolate* isolate = env->GetIsolate();
1131 v8::HandleScope scope(isolate);
1132 v8::Handle<v8::Value> value;
1133 // check int32_t and uint32_t
1134 int32_t int_values[] = {
1136 i::Smi::kMinValue, i::Smi::kMaxValue
1138 for (size_t i = 0; i < arraysize(int_values); i++) {
1139 for (int modifier = -1; modifier <= 1; modifier++) {
1140 int int_value = int_values[i] + modifier;
1142 fast_return_value_int32 = int_value;
1143 value = TestFastReturnValues<int32_t>();
1144 CHECK(value->IsInt32());
1145 CHECK(fast_return_value_int32 == value->Int32Value());
1147 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1148 value = TestFastReturnValues<uint32_t>();
1149 CHECK(value->IsUint32());
1150 CHECK(fast_return_value_uint32 == value->Uint32Value());
1154 value = TestFastReturnValues<double>();
1155 CHECK(value->IsNumber());
1156 CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
1157 // check bool values
1158 for (int i = 0; i < 2; i++) {
1159 fast_return_value_bool = i == 0;
1160 value = TestFastReturnValues<bool>();
1161 CHECK(value->IsBoolean());
1162 CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
1165 ReturnValueOddball oddballs[] = {
1167 kUndefinedReturnValue,
1168 kEmptyStringReturnValue
1170 for (size_t i = 0; i < arraysize(oddballs); i++) {
1171 fast_return_value_void = oddballs[i];
1172 value = TestFastReturnValues<void>();
1173 switch (fast_return_value_void) {
1174 case kNullReturnValue:
1175 CHECK(value->IsNull());
1177 case kUndefinedReturnValue:
1178 CHECK(value->IsUndefined());
1180 case kEmptyStringReturnValue:
1181 CHECK(value->IsString());
1182 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1187 fast_return_value_object_is_empty = false;
1188 value = TestFastReturnValues<Object>();
1189 CHECK(value->IsObject());
1190 fast_return_value_object_is_empty = true;
1191 value = TestFastReturnValues<Object>();
1192 CHECK(value->IsUndefined());
1196 THREADED_TEST(FunctionTemplateSetLength) {
1198 v8::Isolate* isolate = env->GetIsolate();
1199 v8::HandleScope scope(isolate);
1201 Local<v8::FunctionTemplate> fun_templ =
1202 v8::FunctionTemplate::New(isolate,
1204 Handle<v8::Value>(),
1205 Handle<v8::Signature>(),
1207 Local<Function> fun = fun_templ->GetFunction();
1208 env->Global()->Set(v8_str("obj"), fun);
1209 Local<Script> script = v8_compile("obj.length");
1210 CHECK_EQ(23, script->Run()->Int32Value());
1213 Local<v8::FunctionTemplate> fun_templ =
1214 v8::FunctionTemplate::New(isolate, handle_callback);
1215 fun_templ->SetLength(22);
1216 Local<Function> fun = fun_templ->GetFunction();
1217 env->Global()->Set(v8_str("obj"), fun);
1218 Local<Script> script = v8_compile("obj.length");
1219 CHECK_EQ(22, script->Run()->Int32Value());
1222 // Without setting length it defaults to 0.
1223 Local<v8::FunctionTemplate> fun_templ =
1224 v8::FunctionTemplate::New(isolate, handle_callback);
1225 Local<Function> fun = fun_templ->GetFunction();
1226 env->Global()->Set(v8_str("obj"), fun);
1227 Local<Script> script = v8_compile("obj.length");
1228 CHECK_EQ(0, script->Run()->Int32Value());
1233 static void* expected_ptr;
1234 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1235 void* ptr = v8::External::Cast(*args.Data())->Value();
1236 CHECK_EQ(expected_ptr, ptr);
1237 args.GetReturnValue().Set(true);
1241 static void TestExternalPointerWrapping() {
1243 v8::Isolate* isolate = env->GetIsolate();
1244 v8::HandleScope scope(isolate);
1246 v8::Handle<v8::Value> data =
1247 v8::External::New(isolate, expected_ptr);
1249 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1250 obj->Set(v8_str("func"),
1251 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1252 env->Global()->Set(v8_str("obj"), obj);
1255 "function foo() {\n"
1256 " for (var i = 0; i < 13; i++) obj.func();\n"
1258 "foo(), true")->BooleanValue());
1262 THREADED_TEST(ExternalWrap) {
1263 // Check heap allocated object.
1266 TestExternalPointerWrapping();
1269 // Check stack allocated object.
1271 expected_ptr = &foo;
1272 TestExternalPointerWrapping();
1274 // Check not aligned addresses.
1276 char* s = new char[n];
1277 for (int i = 0; i < n; i++) {
1278 expected_ptr = s + i;
1279 TestExternalPointerWrapping();
1284 // Check several invalid addresses.
1285 expected_ptr = reinterpret_cast<void*>(1);
1286 TestExternalPointerWrapping();
1288 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1289 TestExternalPointerWrapping();
1291 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1292 TestExternalPointerWrapping();
1294 #if defined(V8_HOST_ARCH_X64)
1295 // Check a value with a leading 1 bit in x64 Smi encoding.
1296 expected_ptr = reinterpret_cast<void*>(0x400000000);
1297 TestExternalPointerWrapping();
1299 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1300 TestExternalPointerWrapping();
1302 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1303 TestExternalPointerWrapping();
1308 THREADED_TEST(FindInstanceInPrototypeChain) {
1310 v8::Isolate* isolate = env->GetIsolate();
1311 v8::HandleScope scope(isolate);
1313 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1314 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1315 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1316 derived->Inherit(base);
1318 Local<v8::Function> base_function = base->GetFunction();
1319 Local<v8::Function> derived_function = derived->GetFunction();
1320 Local<v8::Function> other_function = other->GetFunction();
1322 Local<v8::Object> base_instance = base_function->NewInstance();
1323 Local<v8::Object> derived_instance = derived_function->NewInstance();
1324 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1325 Local<v8::Object> other_instance = other_function->NewInstance();
1326 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1327 other_instance->Set(v8_str("__proto__"), derived_instance2);
1329 // base_instance is only an instance of base.
1331 base_instance->Equals(base_instance->FindInstanceInPrototypeChain(base)));
1332 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1333 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1335 // derived_instance is an instance of base and derived.
1336 CHECK(derived_instance->Equals(
1337 derived_instance->FindInstanceInPrototypeChain(base)));
1338 CHECK(derived_instance->Equals(
1339 derived_instance->FindInstanceInPrototypeChain(derived)));
1340 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1342 // other_instance is an instance of other and its immediate
1343 // prototype derived_instance2 is an instance of base and derived.
1344 // Note, derived_instance is an instance of base and derived too,
1345 // but it comes after derived_instance2 in the prototype chain of
1347 CHECK(derived_instance2->Equals(
1348 other_instance->FindInstanceInPrototypeChain(base)));
1349 CHECK(derived_instance2->Equals(
1350 other_instance->FindInstanceInPrototypeChain(derived)));
1351 CHECK(other_instance->Equals(
1352 other_instance->FindInstanceInPrototypeChain(other)));
1356 THREADED_TEST(TinyInteger) {
1358 v8::Isolate* isolate = env->GetIsolate();
1359 v8::HandleScope scope(isolate);
1361 int32_t value = 239;
1362 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1363 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1365 value_obj = v8::Integer::New(isolate, value);
1366 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1370 THREADED_TEST(BigSmiInteger) {
1372 v8::HandleScope scope(env->GetIsolate());
1373 v8::Isolate* isolate = CcTest::isolate();
1375 int32_t value = i::Smi::kMaxValue;
1376 // We cannot add one to a Smi::kMaxValue without wrapping.
1377 if (i::SmiValuesAre31Bits()) {
1378 CHECK(i::Smi::IsValid(value));
1379 CHECK(!i::Smi::IsValid(value + 1));
1381 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1382 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1384 value_obj = v8::Integer::New(isolate, value);
1385 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1390 THREADED_TEST(BigInteger) {
1392 v8::HandleScope scope(env->GetIsolate());
1393 v8::Isolate* isolate = CcTest::isolate();
1395 // We cannot add one to a Smi::kMaxValue without wrapping.
1396 if (i::SmiValuesAre31Bits()) {
1397 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1398 // The code will not be run in that case, due to the "if" guard.
1400 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1401 CHECK(value > i::Smi::kMaxValue);
1402 CHECK(!i::Smi::IsValid(value));
1404 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1405 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1407 value_obj = v8::Integer::New(isolate, value);
1408 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1413 THREADED_TEST(TinyUnsignedInteger) {
1415 v8::HandleScope scope(env->GetIsolate());
1416 v8::Isolate* isolate = CcTest::isolate();
1418 uint32_t value = 239;
1420 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1421 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1423 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1424 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1428 THREADED_TEST(BigUnsignedSmiInteger) {
1430 v8::HandleScope scope(env->GetIsolate());
1431 v8::Isolate* isolate = CcTest::isolate();
1433 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1434 CHECK(i::Smi::IsValid(value));
1435 CHECK(!i::Smi::IsValid(value + 1));
1437 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1438 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1440 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1441 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1445 THREADED_TEST(BigUnsignedInteger) {
1447 v8::HandleScope scope(env->GetIsolate());
1448 v8::Isolate* isolate = CcTest::isolate();
1450 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1451 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1452 CHECK(!i::Smi::IsValid(value));
1454 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1455 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1457 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1458 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1462 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1464 v8::HandleScope scope(env->GetIsolate());
1465 v8::Isolate* isolate = CcTest::isolate();
1467 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1468 uint32_t value = INT32_MAX_AS_UINT + 1;
1469 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1471 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1472 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1474 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1475 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1479 THREADED_TEST(IsNativeError) {
1481 v8::HandleScope scope(env->GetIsolate());
1482 v8::Handle<Value> syntax_error = CompileRun(
1483 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1484 CHECK(syntax_error->IsNativeError());
1485 v8::Handle<Value> not_error = CompileRun("{a:42}");
1486 CHECK(!not_error->IsNativeError());
1487 v8::Handle<Value> not_object = CompileRun("42");
1488 CHECK(!not_object->IsNativeError());
1492 THREADED_TEST(IsGeneratorFunctionOrObject) {
1494 v8::HandleScope scope(env->GetIsolate());
1496 CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1497 v8::Handle<Value> gen = CompileRun("gen");
1498 v8::Handle<Value> genObj = CompileRun("gen()");
1499 v8::Handle<Value> object = CompileRun("{a:42}");
1500 v8::Handle<Value> func = CompileRun("func");
1502 CHECK(gen->IsGeneratorFunction());
1503 CHECK(gen->IsFunction());
1504 CHECK(!gen->IsGeneratorObject());
1506 CHECK(!genObj->IsGeneratorFunction());
1507 CHECK(!genObj->IsFunction());
1508 CHECK(genObj->IsGeneratorObject());
1510 CHECK(!object->IsGeneratorFunction());
1511 CHECK(!object->IsFunction());
1512 CHECK(!object->IsGeneratorObject());
1514 CHECK(!func->IsGeneratorFunction());
1515 CHECK(func->IsFunction());
1516 CHECK(!func->IsGeneratorObject());
1520 THREADED_TEST(ArgumentsObject) {
1522 v8::HandleScope scope(env->GetIsolate());
1523 v8::Handle<Value> arguments_object =
1524 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1525 CHECK(arguments_object->IsArgumentsObject());
1526 v8::Handle<Value> array = CompileRun("[1,2,3]");
1527 CHECK(!array->IsArgumentsObject());
1528 v8::Handle<Value> object = CompileRun("{a:42}");
1529 CHECK(!object->IsArgumentsObject());
1533 THREADED_TEST(IsMapOrSet) {
1535 v8::HandleScope scope(env->GetIsolate());
1536 v8::Handle<Value> map = CompileRun("new Map()");
1537 v8::Handle<Value> set = CompileRun("new Set()");
1538 v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1539 v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1540 CHECK(map->IsMap());
1541 CHECK(set->IsSet());
1542 CHECK(weak_map->IsWeakMap());
1543 CHECK(weak_set->IsWeakSet());
1545 CHECK(!map->IsSet());
1546 CHECK(!map->IsWeakMap());
1547 CHECK(!map->IsWeakSet());
1549 CHECK(!set->IsMap());
1550 CHECK(!set->IsWeakMap());
1551 CHECK(!set->IsWeakSet());
1553 CHECK(!weak_map->IsMap());
1554 CHECK(!weak_map->IsSet());
1555 CHECK(!weak_map->IsWeakSet());
1557 CHECK(!weak_set->IsMap());
1558 CHECK(!weak_set->IsSet());
1559 CHECK(!weak_set->IsWeakMap());
1561 v8::Handle<Value> object = CompileRun("{a:42}");
1562 CHECK(!object->IsMap());
1563 CHECK(!object->IsSet());
1564 CHECK(!object->IsWeakMap());
1565 CHECK(!object->IsWeakSet());
1569 THREADED_TEST(StringObject) {
1571 v8::HandleScope scope(env->GetIsolate());
1572 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1573 CHECK(boxed_string->IsStringObject());
1574 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1575 CHECK(!unboxed_string->IsStringObject());
1576 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1577 CHECK(!boxed_not_string->IsStringObject());
1578 v8::Handle<Value> not_object = CompileRun("0");
1579 CHECK(!not_object->IsStringObject());
1580 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1581 CHECK(!as_boxed.IsEmpty());
1582 Local<v8::String> the_string = as_boxed->ValueOf();
1583 CHECK(!the_string.IsEmpty());
1584 ExpectObject("\"test\"", the_string);
1585 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1586 CHECK(new_boxed_string->IsStringObject());
1587 as_boxed = new_boxed_string.As<v8::StringObject>();
1588 the_string = as_boxed->ValueOf();
1589 CHECK(!the_string.IsEmpty());
1590 ExpectObject("\"test\"", the_string);
1594 THREADED_TEST(NumberObject) {
1596 v8::HandleScope scope(env->GetIsolate());
1597 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1598 CHECK(boxed_number->IsNumberObject());
1599 v8::Handle<Value> unboxed_number = CompileRun("42");
1600 CHECK(!unboxed_number->IsNumberObject());
1601 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1602 CHECK(!boxed_not_number->IsNumberObject());
1603 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1604 CHECK(!as_boxed.IsEmpty());
1605 double the_number = as_boxed->ValueOf();
1606 CHECK_EQ(42.0, the_number);
1607 v8::Handle<v8::Value> new_boxed_number =
1608 v8::NumberObject::New(env->GetIsolate(), 43);
1609 CHECK(new_boxed_number->IsNumberObject());
1610 as_boxed = new_boxed_number.As<v8::NumberObject>();
1611 the_number = as_boxed->ValueOf();
1612 CHECK_EQ(43.0, the_number);
1616 THREADED_TEST(BooleanObject) {
1618 v8::HandleScope scope(env->GetIsolate());
1619 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1620 CHECK(boxed_boolean->IsBooleanObject());
1621 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1622 CHECK(!unboxed_boolean->IsBooleanObject());
1623 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1624 CHECK(!boxed_not_boolean->IsBooleanObject());
1625 v8::Handle<v8::BooleanObject> as_boxed =
1626 boxed_boolean.As<v8::BooleanObject>();
1627 CHECK(!as_boxed.IsEmpty());
1628 bool the_boolean = as_boxed->ValueOf();
1629 CHECK_EQ(true, the_boolean);
1630 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1631 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1632 CHECK(boxed_true->IsBooleanObject());
1633 CHECK(boxed_false->IsBooleanObject());
1634 as_boxed = boxed_true.As<v8::BooleanObject>();
1635 CHECK_EQ(true, as_boxed->ValueOf());
1636 as_boxed = boxed_false.As<v8::BooleanObject>();
1637 CHECK_EQ(false, as_boxed->ValueOf());
1641 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1643 v8::HandleScope scope(env->GetIsolate());
1645 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1646 CHECK(primitive_false->IsBoolean());
1647 CHECK(!primitive_false->IsBooleanObject());
1648 CHECK(!primitive_false->BooleanValue());
1649 CHECK(!primitive_false->IsTrue());
1650 CHECK(primitive_false->IsFalse());
1652 Local<Value> false_value = BooleanObject::New(false);
1653 CHECK(!false_value->IsBoolean());
1654 CHECK(false_value->IsBooleanObject());
1655 CHECK(false_value->BooleanValue());
1656 CHECK(!false_value->IsTrue());
1657 CHECK(!false_value->IsFalse());
1659 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1660 CHECK(!false_boolean_object->IsBoolean());
1661 CHECK(false_boolean_object->IsBooleanObject());
1662 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1663 // CHECK(false_boolean_object->BooleanValue());
1664 CHECK(!false_boolean_object->ValueOf());
1665 CHECK(!false_boolean_object->IsTrue());
1666 CHECK(!false_boolean_object->IsFalse());
1668 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1669 CHECK(primitive_true->IsBoolean());
1670 CHECK(!primitive_true->IsBooleanObject());
1671 CHECK(primitive_true->BooleanValue());
1672 CHECK(primitive_true->IsTrue());
1673 CHECK(!primitive_true->IsFalse());
1675 Local<Value> true_value = BooleanObject::New(true);
1676 CHECK(!true_value->IsBoolean());
1677 CHECK(true_value->IsBooleanObject());
1678 CHECK(true_value->BooleanValue());
1679 CHECK(!true_value->IsTrue());
1680 CHECK(!true_value->IsFalse());
1682 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1683 CHECK(!true_boolean_object->IsBoolean());
1684 CHECK(true_boolean_object->IsBooleanObject());
1685 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1686 // CHECK(true_boolean_object->BooleanValue());
1687 CHECK(true_boolean_object->ValueOf());
1688 CHECK(!true_boolean_object->IsTrue());
1689 CHECK(!true_boolean_object->IsFalse());
1693 THREADED_TEST(Number) {
1695 v8::HandleScope scope(env->GetIsolate());
1696 double PI = 3.1415926;
1697 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1698 CHECK_EQ(PI, pi_obj->NumberValue());
1702 THREADED_TEST(ToNumber) {
1704 v8::Isolate* isolate = CcTest::isolate();
1705 v8::HandleScope scope(isolate);
1706 Local<String> str = v8_str("3.1415926");
1707 CHECK_EQ(3.1415926, str->NumberValue());
1708 v8::Handle<v8::Boolean> t = v8::True(isolate);
1709 CHECK_EQ(1.0, t->NumberValue());
1710 v8::Handle<v8::Boolean> f = v8::False(isolate);
1711 CHECK_EQ(0.0, f->NumberValue());
1715 THREADED_TEST(Date) {
1717 v8::HandleScope scope(env->GetIsolate());
1718 double PI = 3.1415926;
1719 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1720 CHECK_EQ(3.0, date->NumberValue());
1721 date.As<v8::Date>()->Set(v8_str("property"),
1722 v8::Integer::New(env->GetIsolate(), 42));
1723 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1727 THREADED_TEST(Boolean) {
1729 v8::Isolate* isolate = env->GetIsolate();
1730 v8::HandleScope scope(isolate);
1731 v8::Handle<v8::Boolean> t = v8::True(isolate);
1733 v8::Handle<v8::Boolean> f = v8::False(isolate);
1735 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1736 CHECK(!u->BooleanValue());
1737 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1738 CHECK(!n->BooleanValue());
1739 v8::Handle<String> str1 = v8_str("");
1740 CHECK(!str1->BooleanValue());
1741 v8::Handle<String> str2 = v8_str("x");
1742 CHECK(str2->BooleanValue());
1743 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1744 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1745 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1746 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1747 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1751 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1752 ApiTestFuzzer::Fuzz();
1753 args.GetReturnValue().Set(v8_num(13.4));
1757 static void GetM(Local<String> name,
1758 const v8::PropertyCallbackInfo<v8::Value>& info) {
1759 ApiTestFuzzer::Fuzz();
1760 info.GetReturnValue().Set(v8_num(876));
1764 THREADED_TEST(GlobalPrototype) {
1765 v8::Isolate* isolate = CcTest::isolate();
1766 v8::HandleScope scope(isolate);
1767 v8::Handle<v8::FunctionTemplate> func_templ =
1768 v8::FunctionTemplate::New(isolate);
1769 func_templ->PrototypeTemplate()->Set(
1770 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1771 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1772 templ->Set(isolate, "x", v8_num(200));
1773 templ->SetAccessor(v8_str("m"), GetM);
1774 LocalContext env(0, templ);
1775 v8::Handle<Script> script(v8_compile("dummy()"));
1776 v8::Handle<Value> result(script->Run());
1777 CHECK_EQ(13.4, result->NumberValue());
1778 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1779 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1783 THREADED_TEST(ObjectTemplate) {
1784 v8::Isolate* isolate = CcTest::isolate();
1785 v8::HandleScope scope(isolate);
1786 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1787 templ1->Set(isolate, "x", v8_num(10));
1788 templ1->Set(isolate, "y", v8_num(13));
1790 Local<v8::Object> instance1 = templ1->NewInstance();
1791 env->Global()->Set(v8_str("p"), instance1);
1792 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1793 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1794 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1795 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1796 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1797 templ2->Set(isolate, "a", v8_num(12));
1798 templ2->Set(isolate, "b", templ1);
1799 Local<v8::Object> instance2 = templ2->NewInstance();
1800 env->Global()->Set(v8_str("q"), instance2);
1801 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1802 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1803 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1804 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1808 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1809 ApiTestFuzzer::Fuzz();
1810 args.GetReturnValue().Set(v8_num(17.2));
1814 static void GetKnurd(Local<String> property,
1815 const v8::PropertyCallbackInfo<v8::Value>& info) {
1816 ApiTestFuzzer::Fuzz();
1817 info.GetReturnValue().Set(v8_num(15.2));
1821 THREADED_TEST(DescriptorInheritance) {
1822 v8::Isolate* isolate = CcTest::isolate();
1823 v8::HandleScope scope(isolate);
1824 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1825 super->PrototypeTemplate()->Set(isolate, "flabby",
1826 v8::FunctionTemplate::New(isolate,
1828 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1830 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1832 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1833 base1->Inherit(super);
1834 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1836 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1837 base2->Inherit(super);
1838 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1842 env->Global()->Set(v8_str("s"), super->GetFunction());
1843 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1844 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1846 // Checks right __proto__ chain.
1847 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1848 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1850 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1852 // Instance accessor should not be visible on function object or its prototype
1853 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1854 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1855 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1857 env->Global()->Set(v8_str("obj"),
1858 base1->GetFunction()->NewInstance());
1859 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1860 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1861 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1862 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1863 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1865 env->Global()->Set(v8_str("obj2"),
1866 base2->GetFunction()->NewInstance());
1867 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1868 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1869 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1870 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1871 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1873 // base1 and base2 cannot cross reference to each's prototype
1874 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1875 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1879 // Helper functions for Interceptor/Accessor interaction tests
1881 void SimpleAccessorGetter(Local<String> name,
1882 const v8::PropertyCallbackInfo<v8::Value>& info) {
1883 Handle<Object> self = Handle<Object>::Cast(info.This());
1884 info.GetReturnValue().Set(
1885 self->Get(String::Concat(v8_str("accessor_"), name)));
1888 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1889 const v8::PropertyCallbackInfo<void>& info) {
1890 Handle<Object> self = Handle<Object>::Cast(info.This());
1891 self->Set(String::Concat(v8_str("accessor_"), name), value);
1894 void SymbolAccessorGetter(Local<Name> name,
1895 const v8::PropertyCallbackInfo<v8::Value>& info) {
1896 CHECK(name->IsSymbol());
1897 Local<Symbol> sym = Local<Symbol>::Cast(name);
1898 if (sym->Name()->IsUndefined())
1900 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
1903 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
1904 const v8::PropertyCallbackInfo<void>& info) {
1905 CHECK(name->IsSymbol());
1906 Local<Symbol> sym = Local<Symbol>::Cast(name);
1907 if (sym->Name()->IsUndefined())
1909 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
1912 void SymbolAccessorGetterReturnsDefault(
1913 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1914 CHECK(name->IsSymbol());
1915 Local<Symbol> sym = Local<Symbol>::Cast(name);
1916 if (sym->Name()->IsUndefined()) return;
1917 info.GetReturnValue().Set(info.Data());
1920 static void ThrowingSymbolAccessorGetter(
1921 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1922 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
1926 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
1927 v8::Isolate* isolate = CcTest::isolate();
1928 v8::HandleScope scope(isolate);
1930 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
1931 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
1932 CHECK(a->map()->instance_descriptors()->IsFixedArray());
1933 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1934 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
1935 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1936 // But we should still have an ExecutableAccessorInfo.
1937 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
1938 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
1939 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
1940 CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
1944 THREADED_TEST(UndefinedIsNotEnumerable) {
1946 v8::HandleScope scope(env->GetIsolate());
1947 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
1948 CHECK(result->IsFalse());
1952 v8::Handle<Script> call_recursively_script;
1953 static const int kTargetRecursionDepth = 200; // near maximum
1956 static void CallScriptRecursivelyCall(
1957 const v8::FunctionCallbackInfo<v8::Value>& args) {
1958 ApiTestFuzzer::Fuzz();
1959 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1960 if (depth == kTargetRecursionDepth) return;
1961 args.This()->Set(v8_str("depth"),
1962 v8::Integer::New(args.GetIsolate(), depth + 1));
1963 args.GetReturnValue().Set(call_recursively_script->Run());
1967 static void CallFunctionRecursivelyCall(
1968 const v8::FunctionCallbackInfo<v8::Value>& args) {
1969 ApiTestFuzzer::Fuzz();
1970 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1971 if (depth == kTargetRecursionDepth) {
1972 printf("[depth = %d]\n", depth);
1975 args.This()->Set(v8_str("depth"),
1976 v8::Integer::New(args.GetIsolate(), depth + 1));
1977 v8::Handle<Value> function =
1978 args.This()->Get(v8_str("callFunctionRecursively"));
1979 args.GetReturnValue().Set(
1980 function.As<Function>()->Call(args.This(), 0, NULL));
1984 THREADED_TEST(DeepCrossLanguageRecursion) {
1985 v8::Isolate* isolate = CcTest::isolate();
1986 v8::HandleScope scope(isolate);
1987 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
1988 global->Set(v8_str("callScriptRecursively"),
1989 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
1990 global->Set(v8_str("callFunctionRecursively"),
1991 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
1992 LocalContext env(NULL, global);
1994 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
1995 call_recursively_script = v8_compile("callScriptRecursively()");
1996 call_recursively_script->Run();
1997 call_recursively_script = v8::Handle<Script>();
1999 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2000 CompileRun("callFunctionRecursively()");
2004 static void ThrowingPropertyHandlerGet(
2005 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2006 // Since this interceptor is used on "with" objects, the runtime will look up
2007 // @@unscopables. Punt.
2008 if (key->IsSymbol()) return;
2009 ApiTestFuzzer::Fuzz();
2010 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2014 static void ThrowingPropertyHandlerSet(
2015 Local<Name> key, Local<Value>,
2016 const v8::PropertyCallbackInfo<v8::Value>& info) {
2017 info.GetIsolate()->ThrowException(key);
2018 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2022 THREADED_TEST(CallbackExceptionRegression) {
2023 v8::Isolate* isolate = CcTest::isolate();
2024 v8::HandleScope scope(isolate);
2025 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2026 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2027 ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2029 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2030 v8::Handle<Value> otto =
2031 CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2032 CHECK(v8_str("otto")->Equals(otto));
2033 v8::Handle<Value> netto =
2034 CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2035 CHECK(v8_str("netto")->Equals(netto));
2039 THREADED_TEST(FunctionPrototype) {
2040 v8::Isolate* isolate = CcTest::isolate();
2041 v8::HandleScope scope(isolate);
2042 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2043 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2045 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2046 Local<Script> script = v8_compile("Foo.prototype.plak");
2047 CHECK_EQ(script->Run()->Int32Value(), 321);
2051 THREADED_TEST(InternalFields) {
2053 v8::Isolate* isolate = env->GetIsolate();
2054 v8::HandleScope scope(isolate);
2056 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2057 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2058 instance_templ->SetInternalFieldCount(1);
2059 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2060 CHECK_EQ(1, obj->InternalFieldCount());
2061 CHECK(obj->GetInternalField(0)->IsUndefined());
2062 obj->SetInternalField(0, v8_num(17));
2063 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2067 THREADED_TEST(GlobalObjectInternalFields) {
2068 v8::Isolate* isolate = CcTest::isolate();
2069 v8::HandleScope scope(isolate);
2070 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2071 global_template->SetInternalFieldCount(1);
2072 LocalContext env(NULL, global_template);
2073 v8::Handle<v8::Object> global_proxy = env->Global();
2074 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2075 CHECK_EQ(1, global->InternalFieldCount());
2076 CHECK(global->GetInternalField(0)->IsUndefined());
2077 global->SetInternalField(0, v8_num(17));
2078 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2082 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2084 v8::HandleScope scope(CcTest::isolate());
2086 v8::Local<v8::Object> global = env->Global();
2087 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2088 CHECK(global->HasRealIndexedProperty(0));
2092 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2094 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2095 obj->SetAlignedPointerInInternalField(0, value);
2096 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2097 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2101 THREADED_TEST(InternalFieldsAlignedPointers) {
2103 v8::Isolate* isolate = env->GetIsolate();
2104 v8::HandleScope scope(isolate);
2106 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2107 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2108 instance_templ->SetInternalFieldCount(1);
2109 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2110 CHECK_EQ(1, obj->InternalFieldCount());
2112 CheckAlignedPointerInInternalField(obj, NULL);
2114 int* heap_allocated = new int[100];
2115 CheckAlignedPointerInInternalField(obj, heap_allocated);
2116 delete[] heap_allocated;
2118 int stack_allocated[100];
2119 CheckAlignedPointerInInternalField(obj, stack_allocated);
2121 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2122 CheckAlignedPointerInInternalField(obj, huge);
2124 v8::Global<v8::Object> persistent(isolate, obj);
2125 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2126 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2130 static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2132 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2133 (*env)->SetAlignedPointerInEmbedderData(index, value);
2134 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2135 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2139 static void* AlignedTestPointer(int i) {
2140 return reinterpret_cast<void*>(i * 1234);
2144 THREADED_TEST(EmbedderDataAlignedPointers) {
2146 v8::HandleScope scope(env->GetIsolate());
2148 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2150 int* heap_allocated = new int[100];
2151 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2152 delete[] heap_allocated;
2154 int stack_allocated[100];
2155 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2157 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2158 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2160 // Test growing of the embedder data's backing store.
2161 for (int i = 0; i < 100; i++) {
2162 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2164 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2165 for (int i = 0; i < 100; i++) {
2166 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2171 static void CheckEmbedderData(LocalContext* env, int index,
2172 v8::Handle<Value> data) {
2173 (*env)->SetEmbedderData(index, data);
2174 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2178 THREADED_TEST(EmbedderData) {
2180 v8::Isolate* isolate = env->GetIsolate();
2181 v8::HandleScope scope(isolate);
2184 &env, 3, v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2185 CheckEmbedderData(&env, 2,
2186 v8::String::NewFromUtf8(isolate, "over the lazy dog."));
2187 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2188 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2192 THREADED_TEST(GetIsolate) {
2194 v8::Isolate* isolate = env->GetIsolate();
2195 v8::HandleScope scope(isolate);
2196 Local<v8::Object> obj = v8::Object::New(isolate);
2197 CHECK_EQ(isolate, obj->GetIsolate());
2198 CHECK_EQ(isolate, CcTest::global()->GetIsolate());
2202 THREADED_TEST(IdentityHash) {
2204 v8::Isolate* isolate = env->GetIsolate();
2205 v8::HandleScope scope(isolate);
2207 // Ensure that the test starts with an fresh heap to test whether the hash
2208 // code is based on the address.
2209 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2210 Local<v8::Object> obj = v8::Object::New(isolate);
2211 int hash = obj->GetIdentityHash();
2212 int hash1 = obj->GetIdentityHash();
2213 CHECK_EQ(hash, hash1);
2214 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2215 // Since the identity hash is essentially a random number two consecutive
2216 // objects should not be assigned the same hash code. If the test below fails
2217 // the random number generator should be evaluated.
2218 CHECK_NE(hash, hash2);
2219 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2220 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2221 // Make sure that the identity hash is not based on the initial address of
2222 // the object alone. If the test below fails the random number generator
2223 // should be evaluated.
2224 CHECK_NE(hash, hash3);
2225 int hash4 = obj->GetIdentityHash();
2226 CHECK_EQ(hash, hash4);
2228 // Check identity hashes behaviour in the presence of JS accessors.
2229 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2231 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2232 Local<v8::Object> o1 = v8::Object::New(isolate);
2233 Local<v8::Object> o2 = v8::Object::New(isolate);
2234 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2238 "function cnst() { return 42; };\n"
2239 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2240 Local<v8::Object> o1 = v8::Object::New(isolate);
2241 Local<v8::Object> o2 = v8::Object::New(isolate);
2242 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2247 THREADED_TEST(GlobalProxyIdentityHash) {
2249 v8::Isolate* isolate = env->GetIsolate();
2250 v8::HandleScope scope(isolate);
2251 Handle<Object> global_proxy = env->Global();
2252 int hash1 = global_proxy->GetIdentityHash();
2253 // Hash should be retained after being detached.
2254 env->DetachGlobal();
2255 int hash2 = global_proxy->GetIdentityHash();
2256 CHECK_EQ(hash1, hash2);
2258 // Re-attach global proxy to a new context, hash should stay the same.
2259 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2260 int hash3 = global_proxy->GetIdentityHash();
2261 CHECK_EQ(hash1, hash3);
2266 TEST(SymbolIdentityHash) {
2268 v8::Isolate* isolate = env->GetIsolate();
2269 v8::HandleScope scope(isolate);
2272 Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
2273 int hash = symbol->GetIdentityHash();
2274 int hash1 = symbol->GetIdentityHash();
2275 CHECK_EQ(hash, hash1);
2276 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2277 int hash3 = symbol->GetIdentityHash();
2278 CHECK_EQ(hash, hash3);
2282 v8::Handle<v8::Symbol> js_symbol =
2283 CompileRun("Symbol('foo')").As<v8::Symbol>();
2284 int hash = js_symbol->GetIdentityHash();
2285 int hash1 = js_symbol->GetIdentityHash();
2286 CHECK_EQ(hash, hash1);
2287 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2288 int hash3 = js_symbol->GetIdentityHash();
2289 CHECK_EQ(hash, hash3);
2294 TEST(StringIdentityHash) {
2296 v8::Isolate* isolate = env->GetIsolate();
2297 v8::HandleScope scope(isolate);
2299 Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
2300 int hash = str->GetIdentityHash();
2301 int hash1 = str->GetIdentityHash();
2302 CHECK_EQ(hash, hash1);
2303 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2304 int hash3 = str->GetIdentityHash();
2305 CHECK_EQ(hash, hash3);
2307 Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
2308 int hash4 = str2->GetIdentityHash();
2309 CHECK_EQ(hash, hash4);
2313 THREADED_TEST(SymbolProperties) {
2315 v8::Isolate* isolate = env->GetIsolate();
2316 v8::HandleScope scope(isolate);
2318 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2319 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2320 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
2321 v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
2323 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2325 // Check basic symbol functionality.
2326 CHECK(sym1->IsSymbol());
2327 CHECK(sym2->IsSymbol());
2328 CHECK(!obj->IsSymbol());
2330 CHECK(sym1->Equals(sym1));
2331 CHECK(sym2->Equals(sym2));
2332 CHECK(!sym1->Equals(sym2));
2333 CHECK(!sym2->Equals(sym1));
2334 CHECK(sym1->StrictEquals(sym1));
2335 CHECK(sym2->StrictEquals(sym2));
2336 CHECK(!sym1->StrictEquals(sym2));
2337 CHECK(!sym2->StrictEquals(sym1));
2339 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2341 v8::Local<v8::Value> sym_val = sym2;
2342 CHECK(sym_val->IsSymbol());
2343 CHECK(sym_val->Equals(sym2));
2344 CHECK(sym_val->StrictEquals(sym2));
2345 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2347 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2348 CHECK(sym_obj->IsSymbolObject());
2349 CHECK(!sym2->IsSymbolObject());
2350 CHECK(!obj->IsSymbolObject());
2351 CHECK(!sym_obj->Equals(sym2));
2352 CHECK(!sym_obj->StrictEquals(sym2));
2353 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2354 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2356 // Make sure delete of a non-existent symbol property works.
2357 CHECK(obj->Delete(sym1));
2358 CHECK(!obj->Has(sym1));
2360 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2361 CHECK(obj->Has(sym1));
2362 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2363 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2364 CHECK(obj->Has(sym1));
2365 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2366 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2368 CHECK_EQ(0u, obj->GetOwnPropertyNames()->Length());
2369 unsigned num_props = obj->GetPropertyNames()->Length();
2370 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2371 v8::Integer::New(isolate, 20)));
2372 CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2373 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2375 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2377 CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2378 CHECK(obj->Get(sym3)->IsUndefined());
2379 CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2380 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2381 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2382 ->Equals(v8::Integer::New(isolate, 42)));
2384 // Add another property and delete it afterwards to force the object in
2386 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2387 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2388 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2389 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2390 CHECK_EQ(2u, obj->GetOwnPropertyNames()->Length());
2392 CHECK(obj->Has(sym1));
2393 CHECK(obj->Has(sym2));
2394 CHECK(obj->Has(sym3));
2395 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2396 CHECK(obj->Delete(sym2));
2397 CHECK(obj->Has(sym1));
2398 CHECK(!obj->Has(sym2));
2399 CHECK(obj->Has(sym3));
2400 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2401 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2402 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2403 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2404 ->Equals(v8::Integer::New(isolate, 42)));
2405 CHECK_EQ(2u, obj->GetOwnPropertyNames()->Length());
2407 // Symbol properties are inherited.
2408 v8::Local<v8::Object> child = v8::Object::New(isolate);
2409 child->SetPrototype(obj);
2410 CHECK(child->Has(sym1));
2411 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2412 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2413 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2414 ->Equals(v8::Integer::New(isolate, 42)));
2415 CHECK_EQ(0u, child->GetOwnPropertyNames()->Length());
2419 THREADED_TEST(SymbolTemplateProperties) {
2421 v8::Isolate* isolate = env->GetIsolate();
2422 v8::HandleScope scope(isolate);
2423 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
2424 v8::Local<v8::Name> name = v8::Symbol::New(isolate);
2425 CHECK(!name.IsEmpty());
2426 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
2427 v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
2428 CHECK(!new_instance.IsEmpty());
2429 CHECK(new_instance->Has(name));
2433 THREADED_TEST(PrivateProperties) {
2435 v8::Isolate* isolate = env->GetIsolate();
2436 v8::HandleScope scope(isolate);
2438 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2439 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2440 v8::Local<v8::Private> priv2 =
2441 v8::Private::New(isolate, v8_str("my-private"));
2443 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2445 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2447 // Make sure delete of a non-existent private symbol property works.
2448 CHECK(obj->DeletePrivate(priv1));
2449 CHECK(!obj->HasPrivate(priv1));
2451 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2452 CHECK(obj->HasPrivate(priv1));
2453 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2454 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2455 CHECK(obj->HasPrivate(priv1));
2456 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2458 CHECK_EQ(0u, obj->GetOwnPropertyNames()->Length());
2459 unsigned num_props = obj->GetPropertyNames()->Length();
2460 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2461 v8::Integer::New(isolate, 20)));
2462 CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2463 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2465 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2467 // Add another property and delete it afterwards to force the object in
2469 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2470 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2471 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2472 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2473 CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2475 CHECK(obj->HasPrivate(priv1));
2476 CHECK(obj->HasPrivate(priv2));
2477 CHECK(obj->DeletePrivate(priv2));
2478 CHECK(obj->HasPrivate(priv1));
2479 CHECK(!obj->HasPrivate(priv2));
2480 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2481 CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2483 // Private properties are inherited (for the time being).
2484 v8::Local<v8::Object> child = v8::Object::New(isolate);
2485 child->SetPrototype(obj);
2486 CHECK(child->HasPrivate(priv1));
2487 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2488 CHECK_EQ(0u, child->GetOwnPropertyNames()->Length());
2492 THREADED_TEST(GlobalSymbols) {
2494 v8::Isolate* isolate = env->GetIsolate();
2495 v8::HandleScope scope(isolate);
2497 v8::Local<String> name = v8_str("my-symbol");
2498 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2499 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2500 CHECK(glob2->SameValue(glob));
2502 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2503 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2504 CHECK(glob_api2->SameValue(glob_api));
2505 CHECK(!glob_api->SameValue(glob));
2507 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2508 CHECK(!sym->SameValue(glob));
2510 CompileRun("var sym2 = Symbol.for('my-symbol')");
2511 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2512 CHECK(sym2->SameValue(glob));
2513 CHECK(!sym2->SameValue(glob_api));
2517 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
2520 v8::Isolate* isolate = env->GetIsolate();
2521 v8::HandleScope scope(isolate);
2523 v8::Local<v8::Symbol> symbol = getter(isolate);
2524 std::string script = std::string("var sym = ") + name;
2525 CompileRun(script.c_str());
2526 v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
2528 CHECK(!value.IsEmpty());
2529 CHECK(!symbol.IsEmpty());
2530 CHECK(value->SameValue(symbol));
2534 THREADED_TEST(WellKnownSymbols) {
2535 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
2536 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
2540 THREADED_TEST(GlobalPrivates) {
2542 v8::Isolate* isolate = env->GetIsolate();
2543 v8::HandleScope scope(isolate);
2545 v8::Local<String> name = v8_str("my-private");
2546 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2547 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2548 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2550 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2551 CHECK(obj->HasPrivate(glob2));
2553 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2554 CHECK(!obj->HasPrivate(priv));
2556 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2557 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2558 CHECK(!obj->Has(intern));
2562 class ScopedArrayBufferContents {
2564 explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
2565 : contents_(contents) {}
2566 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2567 void* Data() const { return contents_.Data(); }
2568 size_t ByteLength() const { return contents_.ByteLength(); }
2571 const v8::ArrayBuffer::Contents contents_;
2574 template <typename T>
2575 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2576 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2577 for (int i = 0; i < value->InternalFieldCount(); i++) {
2578 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2583 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2585 v8::Isolate* isolate = env->GetIsolate();
2586 v8::HandleScope handle_scope(isolate);
2588 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2589 CheckInternalFieldsAreZero(ab);
2590 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2591 CHECK(!ab->IsExternal());
2592 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2594 ScopedArrayBufferContents ab_contents(ab->Externalize());
2595 CHECK(ab->IsExternal());
2597 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2598 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2599 DCHECK(data != NULL);
2600 env->Global()->Set(v8_str("ab"), ab);
2602 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2603 CHECK_EQ(1024, result->Int32Value());
2605 result = CompileRun(
2606 "var u8 = new Uint8Array(ab);"
2610 CHECK_EQ(1024, result->Int32Value());
2611 CHECK_EQ(0xFF, data[0]);
2612 CHECK_EQ(0xAA, data[1]);
2615 result = CompileRun("u8[0] + u8[1]");
2616 CHECK_EQ(0xDD, result->Int32Value());
2620 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2622 v8::Isolate* isolate = env->GetIsolate();
2623 v8::HandleScope handle_scope(isolate);
2626 v8::Local<v8::Value> result = CompileRun(
2627 "var ab1 = new ArrayBuffer(2);"
2628 "var u8_a = new Uint8Array(ab1);"
2630 "u8_a[1] = 0xFF; u8_a.buffer");
2631 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2632 CheckInternalFieldsAreZero(ab1);
2633 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2634 CHECK(!ab1->IsExternal());
2635 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2636 CHECK(ab1->IsExternal());
2638 result = CompileRun("ab1.byteLength");
2639 CHECK_EQ(2, result->Int32Value());
2640 result = CompileRun("u8_a[0]");
2641 CHECK_EQ(0xAA, result->Int32Value());
2642 result = CompileRun("u8_a[1]");
2643 CHECK_EQ(0xFF, result->Int32Value());
2644 result = CompileRun(
2645 "var u8_b = new Uint8Array(ab1);"
2648 CHECK_EQ(0xBB, result->Int32Value());
2649 result = CompileRun("u8_b[1]");
2650 CHECK_EQ(0xFF, result->Int32Value());
2652 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2653 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2654 CHECK_EQ(0xBB, ab1_data[0]);
2655 CHECK_EQ(0xFF, ab1_data[1]);
2658 result = CompileRun("u8_a[0] + u8_a[1]");
2659 CHECK_EQ(0xDD, result->Int32Value());
2663 THREADED_TEST(ArrayBuffer_External) {
2665 v8::Isolate* isolate = env->GetIsolate();
2666 v8::HandleScope handle_scope(isolate);
2668 i::ScopedVector<uint8_t> my_data(100);
2669 memset(my_data.start(), 0, 100);
2670 Local<v8::ArrayBuffer> ab3 =
2671 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
2672 CheckInternalFieldsAreZero(ab3);
2673 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2674 CHECK(ab3->IsExternal());
2676 env->Global()->Set(v8_str("ab3"), ab3);
2678 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2679 CHECK_EQ(100, result->Int32Value());
2681 result = CompileRun(
2682 "var u8_b = new Uint8Array(ab3);"
2686 CHECK_EQ(100, result->Int32Value());
2687 CHECK_EQ(0xBB, my_data[0]);
2688 CHECK_EQ(0xCC, my_data[1]);
2691 result = CompileRun("u8_b[0] + u8_b[1]");
2692 CHECK_EQ(0xDD, result->Int32Value());
2696 THREADED_TEST(ArrayBuffer_DisableNeuter) {
2698 v8::Isolate* isolate = env->GetIsolate();
2699 v8::HandleScope handle_scope(isolate);
2701 i::ScopedVector<uint8_t> my_data(100);
2702 memset(my_data.start(), 0, 100);
2703 Local<v8::ArrayBuffer> ab =
2704 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
2705 CHECK(ab->IsNeuterable());
2707 i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
2708 buf->set_is_neuterable(false);
2710 CHECK(!ab->IsNeuterable());
2714 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
2715 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
2716 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
2720 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
2721 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
2722 CHECK_EQ(0, static_cast<int>(ta->Length()));
2723 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
2727 static void CheckIsTypedArrayVarNeutered(const char* name) {
2728 i::ScopedVector<char> source(1024);
2730 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
2732 CHECK(CompileRun(source.start())->IsTrue());
2733 v8::Handle<v8::TypedArray> ta =
2734 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
2735 CheckIsNeutered(ta);
2739 template <typename TypedArray, int kElementSize>
2740 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
2741 int byteOffset, int length) {
2742 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
2743 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
2744 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
2745 CHECK_EQ(length, static_cast<int>(ta->Length()));
2746 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
2751 THREADED_TEST(ArrayBuffer_NeuteringApi) {
2753 v8::Isolate* isolate = env->GetIsolate();
2754 v8::HandleScope handle_scope(isolate);
2756 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
2758 v8::Handle<v8::Uint8Array> u8a =
2759 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
2760 v8::Handle<v8::Uint8ClampedArray> u8c =
2761 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
2762 v8::Handle<v8::Int8Array> i8a =
2763 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
2765 v8::Handle<v8::Uint16Array> u16a =
2766 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
2767 v8::Handle<v8::Int16Array> i16a =
2768 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
2770 v8::Handle<v8::Uint32Array> u32a =
2771 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
2772 v8::Handle<v8::Int32Array> i32a =
2773 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
2775 v8::Handle<v8::Float32Array> f32a =
2776 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
2777 v8::Handle<v8::Float64Array> f64a =
2778 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
2780 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
2781 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
2782 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
2783 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
2785 ScopedArrayBufferContents contents(buffer->Externalize());
2787 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
2788 CheckIsNeutered(u8a);
2789 CheckIsNeutered(u8c);
2790 CheckIsNeutered(i8a);
2791 CheckIsNeutered(u16a);
2792 CheckIsNeutered(i16a);
2793 CheckIsNeutered(u32a);
2794 CheckIsNeutered(i32a);
2795 CheckIsNeutered(f32a);
2796 CheckIsNeutered(f64a);
2797 CheckDataViewIsNeutered(dv);
2801 THREADED_TEST(ArrayBuffer_NeuteringScript) {
2803 v8::Isolate* isolate = env->GetIsolate();
2804 v8::HandleScope handle_scope(isolate);
2807 "var ab = new ArrayBuffer(1024);"
2808 "var u8a = new Uint8Array(ab, 1, 1023);"
2809 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
2810 "var i8a = new Int8Array(ab, 1, 1023);"
2811 "var u16a = new Uint16Array(ab, 2, 511);"
2812 "var i16a = new Int16Array(ab, 2, 511);"
2813 "var u32a = new Uint32Array(ab, 4, 255);"
2814 "var i32a = new Int32Array(ab, 4, 255);"
2815 "var f32a = new Float32Array(ab, 4, 255);"
2816 "var f64a = new Float64Array(ab, 8, 127);"
2817 "var dv = new DataView(ab, 1, 1023);");
2819 v8::Handle<v8::ArrayBuffer> ab =
2820 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
2822 v8::Handle<v8::DataView> dv =
2823 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
2825 ScopedArrayBufferContents contents(ab->Externalize());
2827 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
2828 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
2830 CheckIsTypedArrayVarNeutered("u8a");
2831 CheckIsTypedArrayVarNeutered("u8c");
2832 CheckIsTypedArrayVarNeutered("i8a");
2833 CheckIsTypedArrayVarNeutered("u16a");
2834 CheckIsTypedArrayVarNeutered("i16a");
2835 CheckIsTypedArrayVarNeutered("u32a");
2836 CheckIsTypedArrayVarNeutered("i32a");
2837 CheckIsTypedArrayVarNeutered("f32a");
2838 CheckIsTypedArrayVarNeutered("f64a");
2840 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
2841 CheckDataViewIsNeutered(dv);
2845 THREADED_TEST(HiddenProperties) {
2847 v8::Isolate* isolate = env->GetIsolate();
2848 v8::HandleScope scope(isolate);
2850 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
2851 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2852 v8::Local<v8::String> empty = v8_str("");
2853 v8::Local<v8::String> prop_name = v8_str("prop_name");
2855 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2857 // Make sure delete of a non-existent hidden value works
2858 CHECK(obj->DeleteHiddenValue(key));
2860 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
2861 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2862 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
2863 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2865 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2867 // Make sure we do not find the hidden property.
2868 CHECK(!obj->Has(empty));
2869 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2870 CHECK(obj->Get(empty)->IsUndefined());
2871 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2872 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
2873 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2874 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2876 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2878 // Add another property and delete it afterwards to force the object in
2880 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
2881 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2882 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2883 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2884 CHECK(obj->Delete(prop_name));
2885 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2887 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2889 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2890 CHECK(obj->GetHiddenValue(key).IsEmpty());
2892 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
2893 CHECK(obj->DeleteHiddenValue(key));
2894 CHECK(obj->GetHiddenValue(key).IsEmpty());
2898 THREADED_TEST(Regress97784) {
2899 // Regression test for crbug.com/97784
2900 // Messing with the Object.prototype should not have effect on
2901 // hidden properties.
2903 v8::HandleScope scope(env->GetIsolate());
2905 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
2906 v8::Local<v8::String> key = v8_str("hidden");
2909 "set_called = false;"
2910 "Object.defineProperty("
2911 " Object.prototype,"
2913 " {get: function() { return 45; },"
2914 " set: function() { set_called = true; }})");
2916 CHECK(obj->GetHiddenValue(key).IsEmpty());
2917 // Make sure that the getter and setter from Object.prototype is not invoked.
2918 // If it did we would have full access to the hidden properties in
2920 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
2921 ExpectFalse("set_called");
2922 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2926 THREADED_TEST(External) {
2927 v8::HandleScope scope(CcTest::isolate());
2929 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
2931 env->Global()->Set(v8_str("ext"), ext);
2932 Local<Value> reext_obj = CompileRun("this.ext");
2933 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
2934 int* ptr = static_cast<int*>(reext->Value());
2939 // Make sure unaligned pointers are wrapped properly.
2940 char* data = i::StrDup("0123456789");
2941 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
2942 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
2943 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
2944 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
2946 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
2947 CHECK_EQ('0', *char_ptr);
2948 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
2949 CHECK_EQ('1', *char_ptr);
2950 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
2951 CHECK_EQ('2', *char_ptr);
2952 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
2953 CHECK_EQ('3', *char_ptr);
2954 i::DeleteArray(data);
2958 THREADED_TEST(GlobalHandle) {
2959 v8::Isolate* isolate = CcTest::isolate();
2960 v8::Persistent<String> global;
2962 v8::HandleScope scope(isolate);
2963 global.Reset(isolate, v8_str("str"));
2966 v8::HandleScope scope(isolate);
2967 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
2971 v8::HandleScope scope(isolate);
2972 global.Reset(isolate, v8_str("str"));
2975 v8::HandleScope scope(isolate);
2976 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
2982 THREADED_TEST(ResettingGlobalHandle) {
2983 v8::Isolate* isolate = CcTest::isolate();
2984 v8::Persistent<String> global;
2986 v8::HandleScope scope(isolate);
2987 global.Reset(isolate, v8_str("str"));
2989 v8::internal::GlobalHandles* global_handles =
2990 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
2991 int initial_handle_count = global_handles->global_handles_count();
2993 v8::HandleScope scope(isolate);
2994 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
2997 v8::HandleScope scope(isolate);
2998 global.Reset(isolate, v8_str("longer"));
3000 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3002 v8::HandleScope scope(isolate);
3003 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3006 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3010 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3011 v8::Isolate* isolate = CcTest::isolate();
3012 v8::Persistent<String> global;
3014 v8::HandleScope scope(isolate);
3015 global.Reset(isolate, v8_str("str"));
3017 v8::internal::GlobalHandles* global_handles =
3018 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3019 int initial_handle_count = global_handles->global_handles_count();
3021 v8::HandleScope scope(isolate);
3022 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3025 v8::HandleScope scope(isolate);
3026 Local<String> empty;
3027 global.Reset(isolate, empty);
3029 CHECK(global.IsEmpty());
3030 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3035 static v8::Global<T> PassUnique(v8::Global<T> unique) {
3036 return unique.Pass();
3041 static v8::Global<T> ReturnUnique(v8::Isolate* isolate,
3042 const v8::Persistent<T>& global) {
3043 v8::Global<String> unique(isolate, global);
3044 return unique.Pass();
3048 THREADED_TEST(Global) {
3049 v8::Isolate* isolate = CcTest::isolate();
3050 v8::Persistent<String> global;
3052 v8::HandleScope scope(isolate);
3053 global.Reset(isolate, v8_str("str"));
3055 v8::internal::GlobalHandles* global_handles =
3056 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3057 int initial_handle_count = global_handles->global_handles_count();
3059 v8::Global<String> unique(isolate, global);
3060 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3061 // Test assignment via Pass
3063 v8::Global<String> copy = unique.Pass();
3064 CHECK(unique.IsEmpty());
3065 CHECK(copy == global);
3066 CHECK_EQ(initial_handle_count + 1,
3067 global_handles->global_handles_count());
3068 unique = copy.Pass();
3070 // Test ctor via Pass
3072 v8::Global<String> copy(unique.Pass());
3073 CHECK(unique.IsEmpty());
3074 CHECK(copy == global);
3075 CHECK_EQ(initial_handle_count + 1,
3076 global_handles->global_handles_count());
3077 unique = copy.Pass();
3079 // Test pass through function call
3081 v8::Global<String> copy = PassUnique(unique.Pass());
3082 CHECK(unique.IsEmpty());
3083 CHECK(copy == global);
3084 CHECK_EQ(initial_handle_count + 1,
3085 global_handles->global_handles_count());
3086 unique = copy.Pass();
3088 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3090 // Test pass from function call
3092 v8::Global<String> unique = ReturnUnique(isolate, global);
3093 CHECK(unique == global);
3094 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3096 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3103 class TwoPassCallbackData;
3104 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
3105 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data);
3108 class TwoPassCallbackData {
3110 TwoPassCallbackData(v8::Isolate* isolate, int* instance_counter)
3111 : first_pass_called_(false),
3112 second_pass_called_(false),
3114 instance_counter_(instance_counter) {
3115 HandleScope scope(isolate);
3116 i::ScopedVector<char> buffer(40);
3117 i::SNPrintF(buffer, "%p", static_cast<void*>(this));
3119 v8::String::NewFromUtf8(isolate, buffer.start(),
3120 v8::NewStringType::kNormal).ToLocalChecked();
3121 cell_.Reset(isolate, string);
3122 (*instance_counter_)++;
3125 ~TwoPassCallbackData() {
3126 CHECK(first_pass_called_);
3127 CHECK(second_pass_called_);
3128 CHECK(cell_.IsEmpty());
3129 (*instance_counter_)--;
3133 CHECK(!first_pass_called_);
3134 CHECK(!second_pass_called_);
3135 CHECK(!cell_.IsEmpty());
3137 first_pass_called_ = true;
3141 CHECK(first_pass_called_);
3142 CHECK(!second_pass_called_);
3143 CHECK(cell_.IsEmpty());
3144 second_pass_called_ = true;
3149 cell_.SetWeak(this, FirstPassCallback, v8::WeakCallbackType::kParameter);
3152 void MarkTriggerGc() { trigger_gc_ = true; }
3153 bool trigger_gc() { return trigger_gc_; }
3155 int* instance_counter() { return instance_counter_; }
3158 bool first_pass_called_;
3159 bool second_pass_called_;
3161 v8::Global<v8::String> cell_;
3162 int* instance_counter_;
3166 void SecondPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
3167 ApiTestFuzzer::Fuzz();
3168 bool trigger_gc = data.GetParameter()->trigger_gc();
3169 int* instance_counter = data.GetParameter()->instance_counter();
3170 data.GetParameter()->SecondPass();
3171 if (!trigger_gc) return;
3172 auto data_2 = new TwoPassCallbackData(data.GetIsolate(), instance_counter);
3174 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3178 void FirstPassCallback(const v8::WeakCallbackInfo<TwoPassCallbackData>& data) {
3179 data.GetParameter()->FirstPass();
3180 data.SetSecondPassCallback(SecondPassCallback);
3186 TEST(TwoPassPhantomCallbacks) {
3187 auto isolate = CcTest::isolate();
3188 const size_t kLength = 20;
3189 int instance_counter = 0;
3190 for (size_t i = 0; i < kLength; ++i) {
3191 auto data = new TwoPassCallbackData(isolate, &instance_counter);
3194 CHECK_EQ(static_cast<int>(kLength), instance_counter);
3195 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3196 CHECK_EQ(0, instance_counter);
3200 TEST(TwoPassPhantomCallbacksNestedGc) {
3201 auto isolate = CcTest::isolate();
3202 const size_t kLength = 20;
3203 TwoPassCallbackData* array[kLength];
3204 int instance_counter = 0;
3205 for (size_t i = 0; i < kLength; ++i) {
3206 array[i] = new TwoPassCallbackData(isolate, &instance_counter);
3207 array[i]->SetWeak();
3209 array[5]->MarkTriggerGc();
3210 array[10]->MarkTriggerGc();
3211 array[15]->MarkTriggerGc();
3212 CHECK_EQ(static_cast<int>(kLength), instance_counter);
3213 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3214 CHECK_EQ(0, instance_counter);
3218 template <typename K, typename V>
3219 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3221 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V>> MapType;
3222 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3223 struct WeakCallbackDataType {
3227 static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
3229 WeakCallbackDataType* data = new WeakCallbackDataType;
3234 static MapType* MapFromWeakCallbackData(
3235 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3236 return data.GetParameter()->map;
3238 static K KeyFromWeakCallbackData(
3239 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3240 return data.GetParameter()->key;
3242 static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
3243 static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {}
3247 template <typename Map>
3248 static void TestPersistentValueMap() {
3250 v8::Isolate* isolate = env->GetIsolate();
3252 v8::internal::GlobalHandles* global_handles =
3253 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3254 int initial_handle_count = global_handles->global_handles_count();
3255 CHECK_EQ(0, static_cast<int>(map.Size()));
3257 HandleScope scope(isolate);
3258 Local<v8::Object> obj = map.Get(7);
3259 CHECK(obj.IsEmpty());
3260 Local<v8::Object> expected = v8::Object::New(isolate);
3261 map.Set(7, expected);
3262 CHECK_EQ(1, static_cast<int>(map.Size()));
3264 CHECK(expected->Equals(obj));
3266 typename Map::PersistentValueReference ref = map.GetReference(7);
3267 CHECK(expected->Equals(ref.NewLocal(isolate)));
3269 v8::Global<v8::Object> removed = map.Remove(7);
3270 CHECK_EQ(0, static_cast<int>(map.Size()));
3271 CHECK(expected == removed);
3272 removed = map.Remove(7);
3273 CHECK(removed.IsEmpty());
3274 map.Set(8, expected);
3275 CHECK_EQ(1, static_cast<int>(map.Size()));
3276 map.Set(8, expected);
3277 CHECK_EQ(1, static_cast<int>(map.Size()));
3279 typename Map::PersistentValueReference ref;
3280 Local<v8::Object> expected2 = v8::Object::New(isolate);
3281 removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
3282 CHECK_EQ(1, static_cast<int>(map.Size()));
3283 CHECK(expected == removed);
3284 CHECK(expected2->Equals(ref.NewLocal(isolate)));
3287 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3289 reinterpret_cast<v8::internal::Isolate*>(isolate)
3291 ->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3295 CHECK_EQ(0, static_cast<int>(map.Size()));
3296 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3300 TEST(PersistentValueMap) {
3301 // Default case, w/o weak callbacks:
3302 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object>>();
3304 // Custom traits with weak callbacks:
3305 typedef v8::PersistentValueMap<int, v8::Object,
3306 WeakStdMapTraits<int, v8::Object>>
3307 WeakPersistentValueMap;
3308 TestPersistentValueMap<WeakPersistentValueMap>();
3314 void* IntKeyToVoidPointer(int key) { return reinterpret_cast<void*>(key << 1); }
3317 Local<v8::Object> NewObjectForIntKey(
3318 v8::Isolate* isolate, const v8::Global<v8::ObjectTemplate>& templ,
3320 auto local = Local<v8::ObjectTemplate>::New(isolate, templ);
3321 auto obj = local->NewInstance();
3322 obj->SetAlignedPointerInInternalField(0, IntKeyToVoidPointer(key));
3327 template <typename K, typename V>
3328 class PhantomStdMapTraits : public v8::StdMapTraits<K, V> {
3330 typedef typename v8::GlobalValueMap<K, V, PhantomStdMapTraits<K, V>> MapType;
3331 static const v8::PersistentContainerCallbackType kCallbackType =
3332 v8::kWeakWithInternalFields;
3333 struct WeakCallbackDataType {
3337 static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
3339 WeakCallbackDataType* data = new WeakCallbackDataType;
3344 static MapType* MapFromWeakCallbackInfo(
3345 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
3346 return data.GetParameter()->map;
3348 static K KeyFromWeakCallbackInfo(
3349 const v8::WeakCallbackInfo<WeakCallbackDataType>& data) {
3350 return data.GetParameter()->key;
3352 static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
3353 static void Dispose(v8::Isolate* isolate, v8::Global<V> value, K key) {
3354 CHECK_EQ(IntKeyToVoidPointer(key),
3355 v8::Object::GetAlignedPointerFromInternalField(value, 0));
3357 static void DisposeWeak(
3358 v8::Isolate* isolate,
3359 const v8::WeakCallbackInfo<WeakCallbackDataType>& info, K key) {
3360 CHECK_EQ(IntKeyToVoidPointer(key), info.GetInternalField(0));
3361 DisposeCallbackData(info.GetParameter());
3368 TEST(GlobalValueMap) {
3369 typedef v8::GlobalValueMap<int, v8::Object,
3370 PhantomStdMapTraits<int, v8::Object>> Map;
3372 v8::Isolate* isolate = env->GetIsolate();
3373 v8::Global<ObjectTemplate> templ;
3375 HandleScope scope(isolate);
3376 auto t = ObjectTemplate::New(isolate);
3377 t->SetInternalFieldCount(1);
3378 templ.Reset(isolate, t);
3381 v8::internal::GlobalHandles* global_handles =
3382 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3383 int initial_handle_count = global_handles->global_handles_count();
3384 CHECK_EQ(0, static_cast<int>(map.Size()));
3386 HandleScope scope(isolate);
3387 Local<v8::Object> obj = map.Get(7);
3388 CHECK(obj.IsEmpty());
3389 Local<v8::Object> expected = v8::Object::New(isolate);
3390 map.Set(7, expected);
3391 CHECK_EQ(1, static_cast<int>(map.Size()));
3393 CHECK(expected->Equals(obj));
3395 Map::PersistentValueReference ref = map.GetReference(7);
3396 CHECK(expected->Equals(ref.NewLocal(isolate)));
3398 v8::Global<v8::Object> removed = map.Remove(7);
3399 CHECK_EQ(0, static_cast<int>(map.Size()));
3400 CHECK(expected == removed);
3401 removed = map.Remove(7);
3402 CHECK(removed.IsEmpty());
3403 map.Set(8, expected);
3404 CHECK_EQ(1, static_cast<int>(map.Size()));
3405 map.Set(8, expected);
3406 CHECK_EQ(1, static_cast<int>(map.Size()));
3408 Map::PersistentValueReference ref;
3409 Local<v8::Object> expected2 = NewObjectForIntKey(isolate, templ, 8);
3410 removed = map.Set(8, v8::Global<v8::Object>(isolate, expected2), &ref);
3411 CHECK_EQ(1, static_cast<int>(map.Size()));
3412 CHECK(expected == removed);
3413 CHECK(expected2->Equals(ref.NewLocal(isolate)));
3416 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3417 CcTest::i_isolate()->heap()->CollectAllGarbage(
3418 i::Heap::kAbortIncrementalMarkingMask);
3419 CHECK_EQ(0, static_cast<int>(map.Size()));
3420 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3422 HandleScope scope(isolate);
3423 Local<v8::Object> value = NewObjectForIntKey(isolate, templ, 9);
3427 CHECK_EQ(0, static_cast<int>(map.Size()));
3428 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3432 TEST(PersistentValueVector) {
3434 v8::Isolate* isolate = env->GetIsolate();
3435 v8::internal::GlobalHandles* global_handles =
3436 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3437 int handle_count = global_handles->global_handles_count();
3438 HandleScope scope(isolate);
3440 v8::PersistentValueVector<v8::Object> vector(isolate);
3442 Local<v8::Object> obj1 = v8::Object::New(isolate);
3443 Local<v8::Object> obj2 = v8::Object::New(isolate);
3444 v8::Global<v8::Object> obj3(isolate, v8::Object::New(isolate));
3446 CHECK(vector.IsEmpty());
3447 CHECK_EQ(0, static_cast<int>(vector.Size()));
3449 vector.ReserveCapacity(3);
3450 CHECK(vector.IsEmpty());
3452 vector.Append(obj1);
3453 vector.Append(obj2);
3454 vector.Append(obj1);
3455 vector.Append(obj3.Pass());
3456 vector.Append(obj1);
3458 CHECK(!vector.IsEmpty());
3459 CHECK_EQ(5, static_cast<int>(vector.Size()));
3460 CHECK(obj3.IsEmpty());
3461 CHECK(obj1->Equals(vector.Get(0)));
3462 CHECK(obj1->Equals(vector.Get(2)));
3463 CHECK(obj1->Equals(vector.Get(4)));
3464 CHECK(obj2->Equals(vector.Get(1)));
3466 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3469 CHECK(vector.IsEmpty());
3470 CHECK_EQ(0, static_cast<int>(vector.Size()));
3471 CHECK_EQ(handle_count, global_handles->global_handles_count());
3475 THREADED_TEST(GlobalHandleUpcast) {
3476 v8::Isolate* isolate = CcTest::isolate();
3477 v8::HandleScope scope(isolate);
3478 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3479 v8::Persistent<String> global_string(isolate, local);
3480 v8::Persistent<Value>& global_value =
3481 v8::Persistent<Value>::Cast(global_string);
3482 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3483 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3484 global_string.Reset();
3488 THREADED_TEST(HandleEquality) {
3489 v8::Isolate* isolate = CcTest::isolate();
3490 v8::Persistent<String> global1;
3491 v8::Persistent<String> global2;
3493 v8::HandleScope scope(isolate);
3494 global1.Reset(isolate, v8_str("str"));
3495 global2.Reset(isolate, v8_str("str2"));
3497 CHECK_EQ(global1 == global1, true);
3498 CHECK_EQ(global1 != global1, false);
3500 v8::HandleScope scope(isolate);
3501 Local<String> local1 = Local<String>::New(isolate, global1);
3502 Local<String> local2 = Local<String>::New(isolate, global2);
3504 CHECK_EQ(global1 == local1, true);
3505 CHECK_EQ(global1 != local1, false);
3506 CHECK_EQ(local1 == global1, true);
3507 CHECK_EQ(local1 != global1, false);
3509 CHECK_EQ(global1 == local2, false);
3510 CHECK_EQ(global1 != local2, true);
3511 CHECK_EQ(local2 == global1, false);
3512 CHECK_EQ(local2 != global1, true);
3514 CHECK_EQ(local1 == local2, false);
3515 CHECK_EQ(local1 != local2, true);
3517 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3518 CHECK_EQ(local1 == anotherLocal1, true);
3519 CHECK_EQ(local1 != anotherLocal1, false);
3526 THREADED_TEST(LocalHandle) {
3527 v8::HandleScope scope(CcTest::isolate());
3528 v8::Local<String> local =
3529 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3530 CHECK_EQ(local->Length(), 3);
3534 class WeakCallCounter {
3536 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
3537 int id() { return id_; }
3538 void increment() { number_of_weak_calls_++; }
3539 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3543 int number_of_weak_calls_;
3547 template <typename T>
3548 struct WeakCallCounterAndPersistent {
3549 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3550 : counter(counter) {}
3551 WeakCallCounter* counter;
3552 v8::Persistent<T> handle;
3556 template <typename T>
3557 static void WeakPointerCallback(
3558 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T>>& data) {
3559 CHECK_EQ(1234, data.GetParameter()->counter->id());
3560 data.GetParameter()->counter->increment();
3561 data.GetParameter()->handle.Reset();
3565 template <typename T>
3566 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3567 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3571 THREADED_TEST(ApiObjectGroups) {
3573 v8::Isolate* iso = env->GetIsolate();
3574 HandleScope scope(iso);
3576 WeakCallCounter counter(1234);
3578 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3579 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3580 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3581 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3582 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3583 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3586 HandleScope scope(iso);
3587 g1s1.handle.Reset(iso, Object::New(iso));
3588 g1s2.handle.Reset(iso, Object::New(iso));
3589 g1c1.handle.Reset(iso, Object::New(iso));
3590 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3591 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3592 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3594 g2s1.handle.Reset(iso, Object::New(iso));
3595 g2s2.handle.Reset(iso, Object::New(iso));
3596 g2c1.handle.Reset(iso, Object::New(iso));
3597 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3598 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3599 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3602 WeakCallCounterAndPersistent<Value> root(&counter);
3603 root.handle.Reset(iso, g1s1.handle); // make a root.
3605 // Connect group 1 and 2, make a cycle.
3607 HandleScope scope(iso);
3608 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())
3609 ->Set(0, Local<Value>::New(iso, g2s2.handle)));
3610 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())
3611 ->Set(0, Local<Value>::New(iso, g1s1.handle)));
3615 UniqueId id1 = MakeUniqueId(g1s1.handle);
3616 UniqueId id2 = MakeUniqueId(g2s2.handle);
3617 iso->SetObjectGroupId(g1s1.handle, id1);
3618 iso->SetObjectGroupId(g1s2.handle, id1);
3619 iso->SetReferenceFromGroup(id1, g1c1.handle);
3620 iso->SetObjectGroupId(g2s1.handle, id2);
3621 iso->SetObjectGroupId(g2s2.handle, id2);
3622 iso->SetReferenceFromGroup(id2, g2c1.handle);
3624 // Do a single full GC, ensure incremental marking is stopped.
3625 v8::internal::Heap* heap =
3626 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3627 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3629 // All object should be alive.
3630 CHECK_EQ(0, counter.NumberOfWeakCalls());
3633 root.handle.SetWeak(&root, &WeakPointerCallback);
3634 // But make children strong roots---all the objects (except for children)
3635 // should be collectable now.
3636 g1c1.handle.ClearWeak();
3637 g2c1.handle.ClearWeak();
3639 // Groups are deleted, rebuild groups.
3641 UniqueId id1 = MakeUniqueId(g1s1.handle);
3642 UniqueId id2 = MakeUniqueId(g2s2.handle);
3643 iso->SetObjectGroupId(g1s1.handle, id1);
3644 iso->SetObjectGroupId(g1s2.handle, id1);
3645 iso->SetReferenceFromGroup(id1, g1c1.handle);
3646 iso->SetObjectGroupId(g2s1.handle, id2);
3647 iso->SetObjectGroupId(g2s2.handle, id2);
3648 iso->SetReferenceFromGroup(id2, g2c1.handle);
3651 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3653 // All objects should be gone. 5 global handles in total.
3654 CHECK_EQ(5, counter.NumberOfWeakCalls());
3656 // And now make children weak again and collect them.
3657 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3658 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3660 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3661 CHECK_EQ(7, counter.NumberOfWeakCalls());
3665 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3667 v8::Isolate* iso = env->GetIsolate();
3668 HandleScope scope(iso);
3670 WeakCallCounter counter(1234);
3672 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3673 WeakCallCounterAndPersistent<String> g1s2(&counter);
3674 WeakCallCounterAndPersistent<String> g1c1(&counter);
3675 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3676 WeakCallCounterAndPersistent<String> g2s2(&counter);
3677 WeakCallCounterAndPersistent<String> g2c1(&counter);
3680 HandleScope scope(iso);
3681 g1s1.handle.Reset(iso, Object::New(iso));
3682 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3683 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3684 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3685 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3686 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3688 g2s1.handle.Reset(iso, Object::New(iso));
3689 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3690 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3691 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3692 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3693 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3696 WeakCallCounterAndPersistent<Value> root(&counter);
3697 root.handle.Reset(iso, g1s1.handle); // make a root.
3699 // Connect group 1 and 2, make a cycle.
3701 HandleScope scope(iso);
3702 CHECK(Local<Object>::New(iso, g1s1.handle)
3703 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3704 CHECK(Local<Object>::New(iso, g2s1.handle)
3705 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3709 UniqueId id1 = MakeUniqueId(g1s1.handle);
3710 UniqueId id2 = MakeUniqueId(g2s2.handle);
3711 iso->SetObjectGroupId(g1s1.handle, id1);
3712 iso->SetObjectGroupId(g1s2.handle, id1);
3713 iso->SetReference(g1s1.handle, g1c1.handle);
3714 iso->SetObjectGroupId(g2s1.handle, id2);
3715 iso->SetObjectGroupId(g2s2.handle, id2);
3716 iso->SetReferenceFromGroup(id2, g2c1.handle);
3718 // Do a single full GC, ensure incremental marking is stopped.
3719 v8::internal::Heap* heap =
3720 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3721 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3723 // All object should be alive.
3724 CHECK_EQ(0, counter.NumberOfWeakCalls());
3727 root.handle.SetWeak(&root, &WeakPointerCallback);
3728 // But make children strong roots---all the objects (except for children)
3729 // should be collectable now.
3730 g1c1.handle.ClearWeak();
3731 g2c1.handle.ClearWeak();
3733 // Groups are deleted, rebuild groups.
3735 UniqueId id1 = MakeUniqueId(g1s1.handle);
3736 UniqueId id2 = MakeUniqueId(g2s2.handle);
3737 iso->SetObjectGroupId(g1s1.handle, id1);
3738 iso->SetObjectGroupId(g1s2.handle, id1);
3739 iso->SetReference(g1s1.handle, g1c1.handle);
3740 iso->SetObjectGroupId(g2s1.handle, id2);
3741 iso->SetObjectGroupId(g2s2.handle, id2);
3742 iso->SetReferenceFromGroup(id2, g2c1.handle);
3745 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3747 // All objects should be gone. 5 global handles in total.
3748 CHECK_EQ(5, counter.NumberOfWeakCalls());
3750 // And now make children weak again and collect them.
3751 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3752 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3754 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3755 CHECK_EQ(7, counter.NumberOfWeakCalls());
3759 THREADED_TEST(ApiObjectGroupsCycle) {
3761 v8::Isolate* iso = env->GetIsolate();
3762 HandleScope scope(iso);
3764 WeakCallCounter counter(1234);
3766 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3767 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3768 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3769 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3770 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3771 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3772 WeakCallCounterAndPersistent<Value> g4s1(&counter);
3773 WeakCallCounterAndPersistent<Value> g4s2(&counter);
3776 HandleScope scope(iso);
3777 g1s1.handle.Reset(iso, Object::New(iso));
3778 g1s2.handle.Reset(iso, Object::New(iso));
3779 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3780 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3781 CHECK(g1s1.handle.IsWeak());
3782 CHECK(g1s2.handle.IsWeak());
3784 g2s1.handle.Reset(iso, Object::New(iso));
3785 g2s2.handle.Reset(iso, Object::New(iso));
3786 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3787 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3788 CHECK(g2s1.handle.IsWeak());
3789 CHECK(g2s2.handle.IsWeak());
3791 g3s1.handle.Reset(iso, Object::New(iso));
3792 g3s2.handle.Reset(iso, Object::New(iso));
3793 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3794 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3795 CHECK(g3s1.handle.IsWeak());
3796 CHECK(g3s2.handle.IsWeak());
3798 g4s1.handle.Reset(iso, Object::New(iso));
3799 g4s2.handle.Reset(iso, Object::New(iso));
3800 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3801 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3802 CHECK(g4s1.handle.IsWeak());
3803 CHECK(g4s2.handle.IsWeak());
3806 WeakCallCounterAndPersistent<Value> root(&counter);
3807 root.handle.Reset(iso, g1s1.handle); // make a root.
3809 // Connect groups. We're building the following cycle:
3810 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3813 UniqueId id1 = MakeUniqueId(g1s1.handle);
3814 UniqueId id2 = MakeUniqueId(g2s1.handle);
3815 UniqueId id3 = MakeUniqueId(g3s1.handle);
3816 UniqueId id4 = MakeUniqueId(g4s1.handle);
3817 iso->SetObjectGroupId(g1s1.handle, id1);
3818 iso->SetObjectGroupId(g1s2.handle, id1);
3819 iso->SetReferenceFromGroup(id1, g2s1.handle);
3820 iso->SetObjectGroupId(g2s1.handle, id2);
3821 iso->SetObjectGroupId(g2s2.handle, id2);
3822 iso->SetReferenceFromGroup(id2, g3s1.handle);
3823 iso->SetObjectGroupId(g3s1.handle, id3);
3824 iso->SetObjectGroupId(g3s2.handle, id3);
3825 iso->SetReferenceFromGroup(id3, g4s1.handle);
3826 iso->SetObjectGroupId(g4s1.handle, id4);
3827 iso->SetObjectGroupId(g4s2.handle, id4);
3828 iso->SetReferenceFromGroup(id4, g1s1.handle);
3830 // Do a single full GC
3831 v8::internal::Heap* heap =
3832 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3833 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3835 // All object should be alive.
3836 CHECK_EQ(0, counter.NumberOfWeakCalls());
3839 root.handle.SetWeak(&root, &WeakPointerCallback);
3841 // Groups are deleted, rebuild groups.
3843 UniqueId id1 = MakeUniqueId(g1s1.handle);
3844 UniqueId id2 = MakeUniqueId(g2s1.handle);
3845 UniqueId id3 = MakeUniqueId(g3s1.handle);
3846 UniqueId id4 = MakeUniqueId(g4s1.handle);
3847 iso->SetObjectGroupId(g1s1.handle, id1);
3848 iso->SetObjectGroupId(g1s2.handle, id1);
3849 iso->SetReferenceFromGroup(id1, g2s1.handle);
3850 iso->SetObjectGroupId(g2s1.handle, id2);
3851 iso->SetObjectGroupId(g2s2.handle, id2);
3852 iso->SetReferenceFromGroup(id2, g3s1.handle);
3853 iso->SetObjectGroupId(g3s1.handle, id3);
3854 iso->SetObjectGroupId(g3s2.handle, id3);
3855 iso->SetReferenceFromGroup(id3, g4s1.handle);
3856 iso->SetObjectGroupId(g4s1.handle, id4);
3857 iso->SetObjectGroupId(g4s2.handle, id4);
3858 iso->SetReferenceFromGroup(id4, g1s1.handle);
3861 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3863 // All objects should be gone. 9 global handles in total.
3864 CHECK_EQ(9, counter.NumberOfWeakCalls());
3868 THREADED_TEST(WeakRootsSurviveTwoRoundsOfGC) {
3870 v8::Isolate* iso = env->GetIsolate();
3871 HandleScope scope(iso);
3873 WeakCallCounter counter(1234);
3875 WeakCallCounterAndPersistent<Value> weak_obj(&counter);
3877 // Create a weak object that references a internalized string.
3879 HandleScope scope(iso);
3880 weak_obj.handle.Reset(iso, Object::New(iso));
3881 weak_obj.handle.SetWeak(&weak_obj, &WeakPointerCallback);
3882 CHECK(weak_obj.handle.IsWeak());
3883 Local<Object>::New(iso, weak_obj.handle.As<Object>())
3884 ->Set(v8_str("x"), String::NewFromUtf8(iso, "magic cookie",
3885 String::kInternalizedString));
3887 // Do a single full GC
3888 i::Isolate* i_iso = reinterpret_cast<v8::internal::Isolate*>(iso);
3889 i::Heap* heap = i_iso->heap();
3890 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3892 // We should have received the weak callback.
3893 CHECK_EQ(1, counter.NumberOfWeakCalls());
3895 // Check that the string is still alive.
3897 HandleScope scope(iso);
3898 i::MaybeHandle<i::String> magic_string =
3899 i::StringTable::LookupStringIfExists(
3901 v8::Utils::OpenHandle(*String::NewFromUtf8(iso, "magic cookie")));
3902 magic_string.Check();
3907 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3908 // on the buildbots, so was made non-threaded for the time being.
3909 TEST(ApiObjectGroupsCycleForScavenger) {
3910 i::FLAG_stress_compaction = false;
3911 i::FLAG_gc_global = false;
3913 v8::Isolate* iso = env->GetIsolate();
3914 HandleScope scope(iso);
3916 WeakCallCounter counter(1234);
3918 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3919 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3920 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3921 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3922 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3923 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3926 HandleScope scope(iso);
3927 g1s1.handle.Reset(iso, Object::New(iso));
3928 g1s2.handle.Reset(iso, Object::New(iso));
3929 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3930 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3932 g2s1.handle.Reset(iso, Object::New(iso));
3933 g2s2.handle.Reset(iso, Object::New(iso));
3934 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3935 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3937 g3s1.handle.Reset(iso, Object::New(iso));
3938 g3s2.handle.Reset(iso, Object::New(iso));
3939 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3940 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3944 WeakCallCounterAndPersistent<Value> root(&counter);
3945 root.handle.Reset(iso, g1s1.handle);
3946 root.handle.MarkPartiallyDependent();
3948 // Connect groups. We're building the following cycle:
3949 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3952 HandleScope handle_scope(iso);
3953 g1s1.handle.MarkPartiallyDependent();
3954 g1s2.handle.MarkPartiallyDependent();
3955 g2s1.handle.MarkPartiallyDependent();
3956 g2s2.handle.MarkPartiallyDependent();
3957 g3s1.handle.MarkPartiallyDependent();
3958 g3s2.handle.MarkPartiallyDependent();
3959 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3960 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3961 Local<Object>::New(iso, g1s1.handle.As<Object>())
3962 ->Set(v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3963 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3964 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3965 Local<Object>::New(iso, g2s1.handle.As<Object>())
3966 ->Set(v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3967 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3968 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3969 Local<Object>::New(iso, g3s1.handle.As<Object>())
3970 ->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3973 v8::internal::Heap* heap =
3974 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3975 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
3977 // All objects should be alive.
3978 CHECK_EQ(0, counter.NumberOfWeakCalls());
3981 root.handle.SetWeak(&root, &WeakPointerCallback);
3982 root.handle.MarkPartiallyDependent();
3984 // Groups are deleted, rebuild groups.
3986 HandleScope handle_scope(iso);
3987 g1s1.handle.MarkPartiallyDependent();
3988 g1s2.handle.MarkPartiallyDependent();
3989 g2s1.handle.MarkPartiallyDependent();
3990 g2s2.handle.MarkPartiallyDependent();
3991 g3s1.handle.MarkPartiallyDependent();
3992 g3s2.handle.MarkPartiallyDependent();
3993 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3994 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3995 Local<Object>::New(iso, g1s1.handle.As<Object>())
3996 ->Set(v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3997 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3998 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3999 Local<Object>::New(iso, g2s1.handle.As<Object>())
4000 ->Set(v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4001 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4002 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4003 Local<Object>::New(iso, g3s1.handle.As<Object>())
4004 ->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4007 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4009 // All objects should be gone. 7 global handles in total.
4010 CHECK_EQ(7, counter.NumberOfWeakCalls());
4014 THREADED_TEST(ScriptException) {
4016 v8::HandleScope scope(env->GetIsolate());
4017 Local<Script> script = v8_compile("throw 'panama!';");
4018 v8::TryCatch try_catch;
4019 Local<Value> result = script->Run();
4020 CHECK(result.IsEmpty());
4021 CHECK(try_catch.HasCaught());
4022 String::Utf8Value exception_value(try_catch.Exception());
4023 CHECK_EQ(0, strcmp(*exception_value, "panama!"));
4027 TEST(TryCatchCustomException) {
4029 v8::Isolate* isolate = env->GetIsolate();
4030 v8::HandleScope scope(isolate);
4031 v8::TryCatch try_catch;
4033 "function CustomError() { this.a = 'b'; }"
4034 "(function f() { throw new CustomError(); })();");
4035 CHECK(try_catch.HasCaught());
4036 CHECK(try_catch.Exception()
4039 ->Equals(v8_str("b")));
4043 bool message_received;
4046 static void check_message_0(v8::Handle<v8::Message> message,
4047 v8::Handle<Value> data) {
4048 CHECK_EQ(5.76, data->NumberValue());
4049 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4050 CHECK(!message->IsSharedCrossOrigin());
4051 message_received = true;
4055 THREADED_TEST(MessageHandler0) {
4056 message_received = false;
4057 v8::HandleScope scope(CcTest::isolate());
4058 CHECK(!message_received);
4059 LocalContext context;
4060 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4061 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4063 CHECK(message_received);
4064 // clear out the message listener
4065 v8::V8::RemoveMessageListeners(check_message_0);
4069 static void check_message_1(v8::Handle<v8::Message> message,
4070 v8::Handle<Value> data) {
4071 CHECK(data->IsNumber());
4072 CHECK_EQ(1337, data->Int32Value());
4073 CHECK(!message->IsSharedCrossOrigin());
4074 message_received = true;
4078 TEST(MessageHandler1) {
4079 message_received = false;
4080 v8::HandleScope scope(CcTest::isolate());
4081 CHECK(!message_received);
4082 v8::V8::AddMessageListener(check_message_1);
4083 LocalContext context;
4084 CompileRun("throw 1337;");
4085 CHECK(message_received);
4086 // clear out the message listener
4087 v8::V8::RemoveMessageListeners(check_message_1);
4091 static void check_message_2(v8::Handle<v8::Message> message,
4092 v8::Handle<Value> data) {
4093 LocalContext context;
4094 CHECK(data->IsObject());
4095 v8::Local<v8::Value> hidden_property =
4096 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4097 CHECK(v8_str("hidden value")->Equals(hidden_property));
4098 CHECK(!message->IsSharedCrossOrigin());
4099 message_received = true;
4103 TEST(MessageHandler2) {
4104 message_received = false;
4105 v8::HandleScope scope(CcTest::isolate());
4106 CHECK(!message_received);
4107 v8::V8::AddMessageListener(check_message_2);
4108 LocalContext context;
4109 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4110 v8::Object::Cast(*error)
4111 ->SetHiddenValue(v8_str("hidden key"), v8_str("hidden value"));
4112 context->Global()->Set(v8_str("error"), error);
4113 CompileRun("throw error;");
4114 CHECK(message_received);
4115 // clear out the message listener
4116 v8::V8::RemoveMessageListeners(check_message_2);
4120 static void check_message_3(v8::Handle<v8::Message> message,
4121 v8::Handle<Value> data) {
4122 CHECK(message->IsSharedCrossOrigin());
4123 CHECK(message->GetScriptOrigin().ResourceIsSharedCrossOrigin()->Value());
4124 CHECK(message->GetScriptOrigin().ResourceIsEmbedderDebugScript()->Value());
4125 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4126 CHECK_EQ(7.40, message->GetScriptOrigin().SourceMapUrl()->NumberValue());
4127 message_received = true;
4131 TEST(MessageHandler3) {
4132 message_received = false;
4133 v8::Isolate* isolate = CcTest::isolate();
4134 v8::HandleScope scope(isolate);
4135 CHECK(!message_received);
4136 v8::V8::AddMessageListener(check_message_3);
4137 LocalContext context;
4138 v8::ScriptOrigin origin = v8::ScriptOrigin(
4139 v8_str("6.75"), v8::Integer::New(isolate, 1),
4140 v8::Integer::New(isolate, 2), v8::True(isolate), Handle<v8::Integer>(),
4141 v8::True(isolate), v8_str("7.40"));
4142 v8::Handle<v8::Script> script =
4143 Script::Compile(v8_str("throw 'error'"), &origin);
4145 CHECK(message_received);
4146 // clear out the message listener
4147 v8::V8::RemoveMessageListeners(check_message_3);
4151 static void check_message_4(v8::Handle<v8::Message> message,
4152 v8::Handle<Value> data) {
4153 CHECK(!message->IsSharedCrossOrigin());
4154 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4155 message_received = true;
4159 TEST(MessageHandler4) {
4160 message_received = false;
4161 v8::Isolate* isolate = CcTest::isolate();
4162 v8::HandleScope scope(isolate);
4163 CHECK(!message_received);
4164 v8::V8::AddMessageListener(check_message_4);
4165 LocalContext context;
4166 v8::ScriptOrigin origin =
4167 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4168 v8::Integer::New(isolate, 2), v8::False(isolate));
4169 v8::Handle<v8::Script> script =
4170 Script::Compile(v8_str("throw 'error'"), &origin);
4172 CHECK(message_received);
4173 // clear out the message listener
4174 v8::V8::RemoveMessageListeners(check_message_4);
4178 static void check_message_5a(v8::Handle<v8::Message> message,
4179 v8::Handle<Value> data) {
4180 CHECK(message->IsSharedCrossOrigin());
4181 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4182 message_received = true;
4186 static void check_message_5b(v8::Handle<v8::Message> message,
4187 v8::Handle<Value> data) {
4188 CHECK(!message->IsSharedCrossOrigin());
4189 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4190 message_received = true;
4194 TEST(MessageHandler5) {
4195 message_received = false;
4196 v8::Isolate* isolate = CcTest::isolate();
4197 v8::HandleScope scope(isolate);
4198 CHECK(!message_received);
4199 v8::V8::AddMessageListener(check_message_5a);
4200 LocalContext context;
4201 v8::ScriptOrigin origin =
4202 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4203 v8::Integer::New(isolate, 2), v8::True(isolate));
4204 v8::Handle<v8::Script> script =
4205 Script::Compile(v8_str("throw 'error'"), &origin);
4207 CHECK(message_received);
4208 // clear out the message listener
4209 v8::V8::RemoveMessageListeners(check_message_5a);
4211 message_received = false;
4212 v8::V8::AddMessageListener(check_message_5b);
4213 origin = v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
4214 v8::Integer::New(isolate, 2), v8::False(isolate));
4215 script = Script::Compile(v8_str("throw 'error'"), &origin);
4217 CHECK(message_received);
4218 // clear out the message listener
4219 v8::V8::RemoveMessageListeners(check_message_5b);
4223 TEST(NativeWeakMap) {
4224 v8::Isolate* isolate = CcTest::isolate();
4225 HandleScope scope(isolate);
4226 Local<v8::NativeWeakMap> weak_map(v8::NativeWeakMap::New(isolate));
4227 CHECK(!weak_map.IsEmpty());
4230 Local<Object> value = v8::Object::New(isolate);
4232 Local<Object> local1 = v8::Object::New(isolate);
4233 CHECK(!weak_map->Has(local1));
4234 CHECK(weak_map->Get(local1)->IsUndefined());
4235 weak_map->Set(local1, value);
4236 CHECK(weak_map->Has(local1));
4237 CHECK(value->Equals(weak_map->Get(local1)));
4239 WeakCallCounter counter(1234);
4240 WeakCallCounterAndPersistent<Value> o1(&counter);
4241 WeakCallCounterAndPersistent<Value> o2(&counter);
4242 WeakCallCounterAndPersistent<Value> s1(&counter);
4244 HandleScope scope(isolate);
4245 Local<v8::Object> obj1 = v8::Object::New(isolate);
4246 Local<v8::Object> obj2 = v8::Object::New(isolate);
4247 Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
4249 weak_map->Set(obj1, value);
4250 weak_map->Set(obj2, value);
4251 weak_map->Set(sym1, value);
4253 o1.handle.Reset(isolate, obj1);
4254 o2.handle.Reset(isolate, obj2);
4255 s1.handle.Reset(isolate, sym1);
4257 CHECK(weak_map->Has(local1));
4258 CHECK(weak_map->Has(obj1));
4259 CHECK(weak_map->Has(obj2));
4260 CHECK(weak_map->Has(sym1));
4262 CHECK(value->Equals(weak_map->Get(local1)));
4263 CHECK(value->Equals(weak_map->Get(obj1)));
4264 CHECK(value->Equals(weak_map->Get(obj2)));
4265 CHECK(value->Equals(weak_map->Get(sym1)));
4267 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
4269 HandleScope scope(isolate);
4270 CHECK(value->Equals(weak_map->Get(local1)));
4271 CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, o1.handle))));
4272 CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, o2.handle))));
4273 CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, s1.handle))));
4276 o1.handle.SetWeak(&o1, &WeakPointerCallback);
4277 o2.handle.SetWeak(&o2, &WeakPointerCallback);
4278 s1.handle.SetWeak(&s1, &WeakPointerCallback);
4280 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
4281 CHECK_EQ(3, counter.NumberOfWeakCalls());
4283 CHECK(o1.handle.IsEmpty());
4284 CHECK(o2.handle.IsEmpty());
4285 CHECK(s1.handle.IsEmpty());
4287 CHECK(value->Equals(weak_map->Get(local1)));
4288 CHECK(weak_map->Delete(local1));
4289 CHECK(!weak_map->Has(local1));
4290 CHECK(weak_map->Get(local1)->IsUndefined());
4294 THREADED_TEST(GetSetProperty) {
4295 LocalContext context;
4296 v8::Isolate* isolate = context->GetIsolate();
4297 v8::HandleScope scope(isolate);
4298 context->Global()->Set(v8_str("foo"), v8_num(14));
4299 context->Global()->Set(v8_str("12"), v8_num(92));
4300 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4301 context->Global()->Set(v8_num(13), v8_num(56));
4302 Local<Value> foo = CompileRun("this.foo");
4303 CHECK_EQ(14, foo->Int32Value());
4304 Local<Value> twelve = CompileRun("this[12]");
4305 CHECK_EQ(92, twelve->Int32Value());
4306 Local<Value> sixteen = CompileRun("this[16]");
4307 CHECK_EQ(32, sixteen->Int32Value());
4308 Local<Value> thirteen = CompileRun("this[13]");
4309 CHECK_EQ(56, thirteen->Int32Value());
4311 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4312 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4313 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4315 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4316 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4317 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4319 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4320 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4321 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4325 THREADED_TEST(PropertyAttributes) {
4326 LocalContext context;
4327 v8::HandleScope scope(context->GetIsolate());
4329 Local<String> prop = v8_str("none");
4330 context->Global()->Set(prop, v8_num(7));
4331 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4333 prop = v8_str("read_only");
4334 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4335 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4336 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4337 CompileRun("read_only = 9");
4338 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4339 context->Global()->Set(prop, v8_num(10));
4340 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4342 prop = v8_str("dont_delete");
4343 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4344 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4345 CompileRun("delete dont_delete");
4346 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4347 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4349 prop = v8_str("dont_enum");
4350 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4351 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4353 prop = v8_str("absent");
4354 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4355 Local<Value> fake_prop = v8_num(1);
4356 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4359 Local<Value> exception =
4360 CompileRun("({ toString: function() { throw 'exception';} })");
4361 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4362 CHECK(try_catch.HasCaught());
4363 String::Utf8Value exception_value(try_catch.Exception());
4364 CHECK_EQ(0, strcmp("exception", *exception_value));
4369 THREADED_TEST(Array) {
4370 LocalContext context;
4371 v8::HandleScope scope(context->GetIsolate());
4372 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4373 CHECK_EQ(0u, array->Length());
4374 CHECK(array->Get(0)->IsUndefined());
4375 CHECK(!array->Has(0));
4376 CHECK(array->Get(100)->IsUndefined());
4377 CHECK(!array->Has(100));
4378 array->Set(2, v8_num(7));
4379 CHECK_EQ(3u, array->Length());
4380 CHECK(!array->Has(0));
4381 CHECK(!array->Has(1));
4382 CHECK(array->Has(2));
4383 CHECK_EQ(7, array->Get(2)->Int32Value());
4384 Local<Value> obj = CompileRun("[1, 2, 3]");
4385 Local<v8::Array> arr = obj.As<v8::Array>();
4386 CHECK_EQ(3u, arr->Length());
4387 CHECK_EQ(1, arr->Get(0)->Int32Value());
4388 CHECK_EQ(2, arr->Get(1)->Int32Value());
4389 CHECK_EQ(3, arr->Get(2)->Int32Value());
4390 array = v8::Array::New(context->GetIsolate(), 27);
4391 CHECK_EQ(27u, array->Length());
4392 array = v8::Array::New(context->GetIsolate(), -27);
4393 CHECK_EQ(0u, array->Length());
4397 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4398 v8::EscapableHandleScope scope(args.GetIsolate());
4399 ApiTestFuzzer::Fuzz();
4400 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4401 for (int i = 0; i < args.Length(); i++) result->Set(i, args[i]);
4402 args.GetReturnValue().Set(scope.Escape(result));
4406 THREADED_TEST(Vector) {
4407 v8::Isolate* isolate = CcTest::isolate();
4408 v8::HandleScope scope(isolate);
4409 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4410 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4411 LocalContext context(0, global);
4413 const char* fun = "f()";
4414 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4415 CHECK_EQ(0u, a0->Length());
4417 const char* fun2 = "f(11)";
4418 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4419 CHECK_EQ(1u, a1->Length());
4420 CHECK_EQ(11, a1->Get(0)->Int32Value());
4422 const char* fun3 = "f(12, 13)";
4423 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4424 CHECK_EQ(2u, a2->Length());
4425 CHECK_EQ(12, a2->Get(0)->Int32Value());
4426 CHECK_EQ(13, a2->Get(1)->Int32Value());
4428 const char* fun4 = "f(14, 15, 16)";
4429 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4430 CHECK_EQ(3u, a3->Length());
4431 CHECK_EQ(14, a3->Get(0)->Int32Value());
4432 CHECK_EQ(15, a3->Get(1)->Int32Value());
4433 CHECK_EQ(16, a3->Get(2)->Int32Value());
4435 const char* fun5 = "f(17, 18, 19, 20)";
4436 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4437 CHECK_EQ(4u, a4->Length());
4438 CHECK_EQ(17, a4->Get(0)->Int32Value());
4439 CHECK_EQ(18, a4->Get(1)->Int32Value());
4440 CHECK_EQ(19, a4->Get(2)->Int32Value());
4441 CHECK_EQ(20, a4->Get(3)->Int32Value());
4445 THREADED_TEST(FunctionCall) {
4446 LocalContext context;
4447 v8::Isolate* isolate = context->GetIsolate();
4448 v8::HandleScope scope(isolate);
4452 " for (var i = 0; i < arguments.length; i++) {"
4453 " result.push(arguments[i]);"
4457 "function ReturnThisSloppy() {"
4460 "function ReturnThisStrict() {"
4464 Local<Function> Foo =
4465 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4466 Local<Function> ReturnThisSloppy =
4467 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4468 Local<Function> ReturnThisStrict =
4469 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4471 v8::Handle<Value>* args0 = NULL;
4472 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4473 CHECK_EQ(0u, a0->Length());
4475 v8::Handle<Value> args1[] = {v8_num(1.1)};
4476 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4477 CHECK_EQ(1u, a1->Length());
4478 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4480 v8::Handle<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
4481 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4482 CHECK_EQ(2u, a2->Length());
4483 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4484 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4486 v8::Handle<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
4487 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4488 CHECK_EQ(3u, a3->Length());
4489 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4490 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4491 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4493 v8::Handle<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
4495 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4496 CHECK_EQ(4u, a4->Length());
4497 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4498 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4499 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4500 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4502 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4503 CHECK(r1->StrictEquals(context->Global()));
4504 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4505 CHECK(r2->StrictEquals(context->Global()));
4506 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4507 CHECK(r3->IsNumberObject());
4508 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4509 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4510 CHECK(r4->IsStringObject());
4511 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4512 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4513 CHECK(r5->IsBooleanObject());
4514 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4516 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4517 CHECK(r6->IsUndefined());
4518 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4519 CHECK(r7->IsNull());
4520 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4521 CHECK(r8->StrictEquals(v8_num(42)));
4522 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4523 CHECK(r9->StrictEquals(v8_str("hello")));
4524 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4525 CHECK(r10->StrictEquals(v8::True(isolate)));
4529 THREADED_TEST(ConstructCall) {
4530 LocalContext context;
4531 v8::Isolate* isolate = context->GetIsolate();
4532 v8::HandleScope scope(isolate);
4536 " for (var i = 0; i < arguments.length; i++) {"
4537 " result.push(arguments[i]);"
4541 Local<Function> Foo =
4542 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4544 v8::Handle<Value>* args0 = NULL;
4545 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4546 CHECK_EQ(0u, a0->Length());
4548 v8::Handle<Value> args1[] = {v8_num(1.1)};
4549 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4550 CHECK_EQ(1u, a1->Length());
4551 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4553 v8::Handle<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
4554 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4555 CHECK_EQ(2u, a2->Length());
4556 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4557 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4559 v8::Handle<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
4560 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4561 CHECK_EQ(3u, a3->Length());
4562 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4563 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4564 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4566 v8::Handle<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
4568 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4569 CHECK_EQ(4u, a4->Length());
4570 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4571 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4572 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4573 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4577 static void CheckUncle(v8::TryCatch* try_catch) {
4578 CHECK(try_catch->HasCaught());
4579 String::Utf8Value str_value(try_catch->Exception());
4580 CHECK_EQ(0, strcmp(*str_value, "uncle?"));
4585 THREADED_TEST(ConversionNumber) {
4587 v8::Isolate* isolate = env->GetIsolate();
4588 v8::HandleScope scope(isolate);
4589 // Very large number.
4590 CompileRun("var obj = Math.pow(2,32) * 1237;");
4591 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4592 CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
4593 CHECK_EQ(0, obj->ToInt32(isolate)->Value());
4595 obj->ToUint32(isolate)->Value()); // NOLINT - no CHECK_EQ for unsigned.
4597 CompileRun("var obj = -1234567890123;");
4598 obj = env->Global()->Get(v8_str("obj"));
4599 CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
4600 CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
4601 CHECK(2382691125u == obj->ToUint32(isolate)->Value()); // NOLINT
4602 // Small positive integer.
4603 CompileRun("var obj = 42;");
4604 obj = env->Global()->Get(v8_str("obj"));
4605 CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
4606 CHECK_EQ(42, obj->ToInt32(isolate)->Value());
4607 CHECK(42u == obj->ToUint32(isolate)->Value()); // NOLINT
4608 // Negative integer.
4609 CompileRun("var obj = -37;");
4610 obj = env->Global()->Get(v8_str("obj"));
4611 CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
4612 CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
4613 CHECK(4294967259u == obj->ToUint32(isolate)->Value()); // NOLINT
4614 // Positive non-int32 integer.
4615 CompileRun("var obj = 0x81234567;");
4616 obj = env->Global()->Get(v8_str("obj"));
4617 CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
4618 CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
4619 CHECK(2166572391u == obj->ToUint32(isolate)->Value()); // NOLINT
4621 CompileRun("var obj = 42.3;");
4622 obj = env->Global()->Get(v8_str("obj"));
4623 CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
4624 CHECK_EQ(42, obj->ToInt32(isolate)->Value());
4625 CHECK(42u == obj->ToUint32(isolate)->Value()); // NOLINT
4626 // Large negative fraction.
4627 CompileRun("var obj = -5726623061.75;");
4628 obj = env->Global()->Get(v8_str("obj"));
4629 CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
4630 CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
4631 CHECK(2863311531u == obj->ToUint32(isolate)->Value()); // NOLINT
4635 THREADED_TEST(isNumberType) {
4637 v8::HandleScope scope(env->GetIsolate());
4638 // Very large number.
4639 CompileRun("var obj = Math.pow(2,32) * 1237;");
4640 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4641 CHECK(!obj->IsInt32());
4642 CHECK(!obj->IsUint32());
4643 // Large negative number.
4644 CompileRun("var obj = -1234567890123;");
4645 obj = env->Global()->Get(v8_str("obj"));
4646 CHECK(!obj->IsInt32());
4647 CHECK(!obj->IsUint32());
4648 // Small positive integer.
4649 CompileRun("var obj = 42;");
4650 obj = env->Global()->Get(v8_str("obj"));
4651 CHECK(obj->IsInt32());
4652 CHECK(obj->IsUint32());
4653 // Negative integer.
4654 CompileRun("var obj = -37;");
4655 obj = env->Global()->Get(v8_str("obj"));
4656 CHECK(obj->IsInt32());
4657 CHECK(!obj->IsUint32());
4658 // Positive non-int32 integer.
4659 CompileRun("var obj = 0x81234567;");
4660 obj = env->Global()->Get(v8_str("obj"));
4661 CHECK(!obj->IsInt32());
4662 CHECK(obj->IsUint32());
4664 CompileRun("var obj = 42.3;");
4665 obj = env->Global()->Get(v8_str("obj"));
4666 CHECK(!obj->IsInt32());
4667 CHECK(!obj->IsUint32());
4668 // Large negative fraction.
4669 CompileRun("var obj = -5726623061.75;");
4670 obj = env->Global()->Get(v8_str("obj"));
4671 CHECK(!obj->IsInt32());
4672 CHECK(!obj->IsUint32());
4674 CompileRun("var obj = 0.0;");
4675 obj = env->Global()->Get(v8_str("obj"));
4676 CHECK(obj->IsInt32());
4677 CHECK(obj->IsUint32());
4679 CompileRun("var obj = -0.0;");
4680 obj = env->Global()->Get(v8_str("obj"));
4681 CHECK(!obj->IsInt32());
4682 CHECK(!obj->IsUint32());
4686 THREADED_TEST(ConversionException) {
4688 v8::Isolate* isolate = env->GetIsolate();
4689 v8::HandleScope scope(isolate);
4691 "function TestClass() { };"
4692 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4693 "var obj = new TestClass();");
4694 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4696 v8::TryCatch try_catch(isolate);
4698 Local<Value> to_string_result = obj->ToString(isolate);
4699 CHECK(to_string_result.IsEmpty());
4700 CheckUncle(&try_catch);
4702 Local<Value> to_number_result = obj->ToNumber(isolate);
4703 CHECK(to_number_result.IsEmpty());
4704 CheckUncle(&try_catch);
4706 Local<Value> to_integer_result = obj->ToInteger(isolate);
4707 CHECK(to_integer_result.IsEmpty());
4708 CheckUncle(&try_catch);
4710 Local<Value> to_uint32_result = obj->ToUint32(isolate);
4711 CHECK(to_uint32_result.IsEmpty());
4712 CheckUncle(&try_catch);
4714 Local<Value> to_int32_result = obj->ToInt32(isolate);
4715 CHECK(to_int32_result.IsEmpty());
4716 CheckUncle(&try_catch);
4718 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
4719 CHECK(to_object_result.IsEmpty());
4720 CHECK(try_catch.HasCaught());
4723 int32_t int32_value = obj->Int32Value();
4724 CHECK_EQ(0, int32_value);
4725 CheckUncle(&try_catch);
4727 uint32_t uint32_value = obj->Uint32Value();
4728 CHECK_EQ(0u, uint32_value);
4729 CheckUncle(&try_catch);
4731 double number_value = obj->NumberValue();
4732 CHECK(std::isnan(number_value));
4733 CheckUncle(&try_catch);
4735 int64_t integer_value = obj->IntegerValue();
4736 CHECK_EQ(0, integer_value);
4737 CheckUncle(&try_catch);
4741 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4742 ApiTestFuzzer::Fuzz();
4743 args.GetIsolate()->ThrowException(v8_str("konto"));
4747 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4748 if (args.Length() < 1) {
4749 args.GetReturnValue().Set(false);
4752 v8::HandleScope scope(args.GetIsolate());
4753 v8::TryCatch try_catch;
4754 Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
4755 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4756 args.GetReturnValue().Set(try_catch.HasCaught());
4760 THREADED_TEST(APICatch) {
4761 v8::Isolate* isolate = CcTest::isolate();
4762 v8::HandleScope scope(isolate);
4763 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4764 templ->Set(v8_str("ThrowFromC"),
4765 v8::FunctionTemplate::New(isolate, ThrowFromC));
4766 LocalContext context(0, templ);
4768 "var thrown = false;"
4774 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4775 CHECK(thrown->BooleanValue());
4779 THREADED_TEST(APIThrowTryCatch) {
4780 v8::Isolate* isolate = CcTest::isolate();
4781 v8::HandleScope scope(isolate);
4782 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4783 templ->Set(v8_str("ThrowFromC"),
4784 v8::FunctionTemplate::New(isolate, ThrowFromC));
4785 LocalContext context(0, templ);
4786 v8::TryCatch try_catch;
4787 CompileRun("ThrowFromC();");
4788 CHECK(try_catch.HasCaught());
4792 // Test that a try-finally block doesn't shadow a try-catch block
4793 // when setting up an external handler.
4795 // BUG(271): Some of the exception propagation does not work on the
4796 // ARM simulator because the simulator separates the C++ stack and the
4797 // JS stack. This test therefore fails on the simulator. The test is
4798 // not threaded to allow the threading tests to run on the simulator.
4799 TEST(TryCatchInTryFinally) {
4800 v8::Isolate* isolate = CcTest::isolate();
4801 v8::HandleScope scope(isolate);
4802 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4803 templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
4804 LocalContext context(0, templ);
4805 Local<Value> result = CompileRun(
4808 " CCatcher('throw 7;');"
4813 CHECK(result->IsTrue());
4817 static void check_reference_error_message(v8::Handle<v8::Message> message,
4818 v8::Handle<v8::Value> data) {
4819 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4820 CHECK(message->Get()->Equals(v8_str(reference_error)));
4824 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4825 ApiTestFuzzer::Fuzz();
4830 // Test that overwritten methods are not invoked on uncaught exception
4831 // formatting. However, they are invoked when performing normal error
4832 // string conversions.
4833 TEST(APIThrowMessageOverwrittenToString) {
4834 v8::Isolate* isolate = CcTest::isolate();
4835 v8::HandleScope scope(isolate);
4836 v8::V8::AddMessageListener(check_reference_error_message);
4837 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4838 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4839 LocalContext context(NULL, templ);
4840 CompileRun("asdf;");
4843 "limit.valueOf = fail;"
4844 "Error.stackTraceLimit = limit;");
4846 CompileRun("Array.prototype.pop = fail;");
4847 CompileRun("Object.prototype.hasOwnProperty = fail;");
4848 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4849 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4850 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4852 "ReferenceError.prototype.toString ="
4853 " function() { return 'Whoops' }");
4854 CompileRun("asdf;");
4855 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4856 CompileRun("asdf;");
4857 CompileRun("ReferenceError.prototype.constructor = void 0;");
4858 CompileRun("asdf;");
4859 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4860 CompileRun("asdf;");
4861 CompileRun("ReferenceError.prototype = new Object();");
4862 CompileRun("asdf;");
4863 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4864 CHECK(string->Equals(v8_str("Whoops")));
4866 "ReferenceError.prototype.constructor = new Object();"
4867 "ReferenceError.prototype.constructor.name = 1;"
4868 "Number.prototype.toString = function() { return 'Whoops'; };"
4869 "ReferenceError.prototype.toString = Object.prototype.toString;");
4870 CompileRun("asdf;");
4871 v8::V8::RemoveMessageListeners(check_reference_error_message);
4875 static void check_custom_error_tostring(v8::Handle<v8::Message> message,
4876 v8::Handle<v8::Value> data) {
4877 const char* uncaught_error = "Uncaught MyError toString";
4878 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4882 TEST(CustomErrorToString) {
4883 LocalContext context;
4884 v8::HandleScope scope(context->GetIsolate());
4885 v8::V8::AddMessageListener(check_custom_error_tostring);
4887 "function MyError(name, message) { "
4888 " this.name = name; "
4889 " this.message = message; "
4891 "MyError.prototype = Object.create(Error.prototype); "
4892 "MyError.prototype.toString = function() { "
4893 " return 'MyError toString'; "
4895 "throw new MyError('my name', 'my message'); ");
4896 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4900 static void check_custom_error_message(v8::Handle<v8::Message> message,
4901 v8::Handle<v8::Value> data) {
4902 const char* uncaught_error = "Uncaught MyError: my message";
4903 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4904 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4908 TEST(CustomErrorMessage) {
4909 LocalContext context;
4910 v8::HandleScope scope(context->GetIsolate());
4911 v8::V8::AddMessageListener(check_custom_error_message);
4915 "function MyError(msg) { "
4916 " this.name = 'MyError'; "
4917 " this.message = msg; "
4919 "MyError.prototype = new Error(); "
4920 "throw new MyError('my message'); ");
4924 "function MyError(msg) { "
4925 " this.name = 'MyError'; "
4926 " this.message = msg; "
4928 "inherits = function(childCtor, parentCtor) { "
4929 " function tempCtor() {}; "
4930 " tempCtor.prototype = parentCtor.prototype; "
4931 " childCtor.superClass_ = parentCtor.prototype; "
4932 " childCtor.prototype = new tempCtor(); "
4933 " childCtor.prototype.constructor = childCtor; "
4935 "inherits(MyError, Error); "
4936 "throw new MyError('my message'); ");
4940 "function MyError(msg) { "
4941 " this.name = 'MyError'; "
4942 " this.message = msg; "
4944 "MyError.prototype = Object.create(Error.prototype); "
4945 "throw new MyError('my message'); ");
4947 v8::V8::RemoveMessageListeners(check_custom_error_message);
4951 static void receive_message(v8::Handle<v8::Message> message,
4952 v8::Handle<v8::Value> data) {
4954 message_received = true;
4958 TEST(APIThrowMessage) {
4959 message_received = false;
4960 v8::Isolate* isolate = CcTest::isolate();
4961 v8::HandleScope scope(isolate);
4962 v8::V8::AddMessageListener(receive_message);
4963 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4964 templ->Set(v8_str("ThrowFromC"),
4965 v8::FunctionTemplate::New(isolate, ThrowFromC));
4966 LocalContext context(0, templ);
4967 CompileRun("ThrowFromC();");
4968 CHECK(message_received);
4969 v8::V8::RemoveMessageListeners(receive_message);
4973 TEST(APIThrowMessageAndVerboseTryCatch) {
4974 message_received = false;
4975 v8::Isolate* isolate = CcTest::isolate();
4976 v8::HandleScope scope(isolate);
4977 v8::V8::AddMessageListener(receive_message);
4978 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4979 templ->Set(v8_str("ThrowFromC"),
4980 v8::FunctionTemplate::New(isolate, ThrowFromC));
4981 LocalContext context(0, templ);
4982 v8::TryCatch try_catch;
4983 try_catch.SetVerbose(true);
4984 Local<Value> result = CompileRun("ThrowFromC();");
4985 CHECK(try_catch.HasCaught());
4986 CHECK(result.IsEmpty());
4987 CHECK(message_received);
4988 v8::V8::RemoveMessageListeners(receive_message);
4992 TEST(APIStackOverflowAndVerboseTryCatch) {
4993 message_received = false;
4994 LocalContext context;
4995 v8::HandleScope scope(context->GetIsolate());
4996 v8::V8::AddMessageListener(receive_message);
4997 v8::TryCatch try_catch;
4998 try_catch.SetVerbose(true);
4999 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5000 CHECK(try_catch.HasCaught());
5001 CHECK(result.IsEmpty());
5002 CHECK(message_received);
5003 v8::V8::RemoveMessageListeners(receive_message);
5007 THREADED_TEST(ExternalScriptException) {
5008 v8::Isolate* isolate = CcTest::isolate();
5009 v8::HandleScope scope(isolate);
5010 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5011 templ->Set(v8_str("ThrowFromC"),
5012 v8::FunctionTemplate::New(isolate, ThrowFromC));
5013 LocalContext context(0, templ);
5015 v8::TryCatch try_catch;
5016 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5017 CHECK(result.IsEmpty());
5018 CHECK(try_catch.HasCaught());
5019 String::Utf8Value exception_value(try_catch.Exception());
5020 CHECK_EQ(0, strcmp("konto", *exception_value));
5024 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5025 ApiTestFuzzer::Fuzz();
5026 CHECK_EQ(4, args.Length());
5027 int count = args[0]->Int32Value();
5028 int cInterval = args[2]->Int32Value();
5030 args.GetIsolate()->ThrowException(v8_str("FromC"));
5033 Local<v8::Object> global = args.GetIsolate()->GetCurrentContext()->Global();
5034 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5035 v8::Handle<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
5036 if (count % cInterval == 0) {
5037 v8::TryCatch try_catch;
5038 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5039 int expected = args[3]->Int32Value();
5040 if (try_catch.HasCaught()) {
5041 CHECK_EQ(expected, count);
5042 CHECK(result.IsEmpty());
5043 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5045 CHECK_NE(expected, count);
5047 args.GetReturnValue().Set(result);
5050 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5057 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5058 ApiTestFuzzer::Fuzz();
5059 CHECK_EQ(3, args.Length());
5060 bool equality = args[0]->BooleanValue();
5061 int count = args[1]->Int32Value();
5062 int expected = args[2]->Int32Value();
5064 CHECK_EQ(count, expected);
5066 CHECK_NE(count, expected);
5071 THREADED_TEST(EvalInTryFinally) {
5072 LocalContext context;
5073 v8::HandleScope scope(context->GetIsolate());
5074 v8::TryCatch try_catch;
5078 " eval('asldkf (*&^&*^');"
5083 CHECK(!try_catch.HasCaught());
5087 // This test works by making a stack of alternating JavaScript and C
5088 // activations. These activations set up exception handlers with regular
5089 // intervals, one interval for C activations and another for JavaScript
5090 // activations. When enough activations have been created an exception is
5091 // thrown and we check that the right activation catches the exception and that
5092 // no other activations do. The right activation is always the topmost one with
5093 // a handler, regardless of whether it is in JavaScript or C.
5095 // The notation used to describe a test case looks like this:
5097 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5099 // Each entry is an activation, either JS or C. The index is the count at that
5100 // level. Stars identify activations with exception handlers, the @ identifies
5101 // the exception handler that should catch the exception.
5103 // BUG(271): Some of the exception propagation does not work on the
5104 // ARM simulator because the simulator separates the C++ stack and the
5105 // JS stack. This test therefore fails on the simulator. The test is
5106 // not threaded to allow the threading tests to run on the simulator.
5107 TEST(ExceptionOrder) {
5108 v8::Isolate* isolate = CcTest::isolate();
5109 v8::HandleScope scope(isolate);
5110 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5111 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5112 templ->Set(v8_str("CThrowCountDown"),
5113 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5114 LocalContext context(0, templ);
5116 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5117 " if (count == 0) throw 'FromJS';"
5118 " if (count % jsInterval == 0) {"
5120 " var value = CThrowCountDown(count - 1,"
5124 " check(false, count, expected);"
5127 " check(true, count, expected);"
5130 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5133 Local<Function> fun =
5134 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5137 // count jsInterval cInterval expected
5139 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5140 v8::Handle<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
5141 fun->Call(fun, argc, a0);
5143 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5144 v8::Handle<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
5145 fun->Call(fun, argc, a1);
5147 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5148 v8::Handle<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
5149 fun->Call(fun, argc, a2);
5151 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5152 v8::Handle<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
5153 fun->Call(fun, argc, a3);
5155 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5156 v8::Handle<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
5157 fun->Call(fun, argc, a4);
5159 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5160 v8::Handle<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
5161 fun->Call(fun, argc, a5);
5165 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5166 ApiTestFuzzer::Fuzz();
5167 CHECK_EQ(1, args.Length());
5168 args.GetIsolate()->ThrowException(args[0]);
5172 THREADED_TEST(ThrowValues) {
5173 v8::Isolate* isolate = CcTest::isolate();
5174 v8::HandleScope scope(isolate);
5175 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5176 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5177 LocalContext context(0, templ);
5178 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5179 "function Run(obj) {"
5185 " return 'no exception';"
5187 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5188 CHECK_EQ(5u, result->Length());
5189 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5190 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5191 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5192 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5193 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5194 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5195 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5199 THREADED_TEST(CatchZero) {
5200 LocalContext context;
5201 v8::HandleScope scope(context->GetIsolate());
5202 v8::TryCatch try_catch;
5203 CHECK(!try_catch.HasCaught());
5204 CompileRun("throw 10");
5205 CHECK(try_catch.HasCaught());
5206 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5208 CHECK(!try_catch.HasCaught());
5209 CompileRun("throw 0");
5210 CHECK(try_catch.HasCaught());
5211 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5215 THREADED_TEST(CatchExceptionFromWith) {
5216 LocalContext context;
5217 v8::HandleScope scope(context->GetIsolate());
5218 v8::TryCatch try_catch;
5219 CHECK(!try_catch.HasCaught());
5220 CompileRun("var o = {}; with (o) { throw 42; }");
5221 CHECK(try_catch.HasCaught());
5225 THREADED_TEST(TryCatchAndFinallyHidingException) {
5226 LocalContext context;
5227 v8::HandleScope scope(context->GetIsolate());
5228 v8::TryCatch try_catch;
5229 CHECK(!try_catch.HasCaught());
5230 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5231 CompileRun("f({toString: function() { throw 42; }});");
5232 CHECK(!try_catch.HasCaught());
5236 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5237 v8::TryCatch try_catch;
5241 THREADED_TEST(TryCatchAndFinally) {
5242 LocalContext context;
5243 v8::Isolate* isolate = context->GetIsolate();
5244 v8::HandleScope scope(isolate);
5245 context->Global()->Set(
5246 v8_str("native_with_try_catch"),
5247 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5248 v8::TryCatch try_catch;
5249 CHECK(!try_catch.HasCaught());
5252 " throw new Error('a');\n"
5254 " native_with_try_catch();\n"
5256 CHECK(try_catch.HasCaught());
5260 static void TryCatchNested1Helper(int depth) {
5262 v8::TryCatch try_catch;
5263 try_catch.SetVerbose(true);
5264 TryCatchNested1Helper(depth - 1);
5265 CHECK(try_catch.HasCaught());
5266 try_catch.ReThrow();
5268 CcTest::isolate()->ThrowException(v8_str("E1"));
5273 static void TryCatchNested2Helper(int depth) {
5275 v8::TryCatch try_catch;
5276 try_catch.SetVerbose(true);
5277 TryCatchNested2Helper(depth - 1);
5278 CHECK(try_catch.HasCaught());
5279 try_catch.ReThrow();
5281 CompileRun("throw 'E2';");
5286 TEST(TryCatchNested) {
5287 v8::V8::Initialize();
5288 LocalContext context;
5289 v8::HandleScope scope(context->GetIsolate());
5292 // Test nested try-catch with a native throw in the end.
5293 v8::TryCatch try_catch;
5294 TryCatchNested1Helper(5);
5295 CHECK(try_catch.HasCaught());
5296 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5300 // Test nested try-catch with a JavaScript throw in the end.
5301 v8::TryCatch try_catch;
5302 TryCatchNested2Helper(5);
5303 CHECK(try_catch.HasCaught());
5304 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5309 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5310 CHECK(try_catch->HasCaught());
5311 Handle<Message> message = try_catch->Message();
5312 Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5313 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5315 strcmp(*v8::String::Utf8Value(message->Get()), "Uncaught Error: a"));
5316 CHECK_EQ(1, message->GetLineNumber());
5317 CHECK_EQ(6, message->GetStartColumn());
5321 void TryCatchMixedNestingHelper(
5322 const v8::FunctionCallbackInfo<v8::Value>& args) {
5323 ApiTestFuzzer::Fuzz();
5324 v8::TryCatch try_catch;
5325 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5326 CHECK(try_catch.HasCaught());
5327 TryCatchMixedNestingCheck(&try_catch);
5328 try_catch.ReThrow();
5332 // This test ensures that an outer TryCatch in the following situation:
5333 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5334 // does not clobber the Message object generated for the inner TryCatch.
5335 // This exercises the ability of TryCatch.ReThrow() to restore the
5336 // inner pending Message before throwing the exception again.
5337 TEST(TryCatchMixedNesting) {
5338 v8::Isolate* isolate = CcTest::isolate();
5339 v8::HandleScope scope(isolate);
5340 v8::V8::Initialize();
5341 v8::TryCatch try_catch;
5342 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5343 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5344 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5345 LocalContext context(0, templ);
5346 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5347 TryCatchMixedNestingCheck(&try_catch);
5351 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5352 ApiTestFuzzer::Fuzz();
5353 v8::TryCatch try_catch;
5354 args.GetIsolate()->ThrowException(v8_str("boom"));
5355 CHECK(try_catch.HasCaught());
5359 TEST(TryCatchNative) {
5360 v8::Isolate* isolate = CcTest::isolate();
5361 v8::HandleScope scope(isolate);
5362 v8::V8::Initialize();
5363 v8::TryCatch try_catch;
5364 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5365 templ->Set(v8_str("TryCatchNativeHelper"),
5366 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5367 LocalContext context(0, templ);
5368 CompileRun("TryCatchNativeHelper();");
5369 CHECK(!try_catch.HasCaught());
5373 void TryCatchNativeResetHelper(
5374 const v8::FunctionCallbackInfo<v8::Value>& args) {
5375 ApiTestFuzzer::Fuzz();
5376 v8::TryCatch try_catch;
5377 args.GetIsolate()->ThrowException(v8_str("boom"));
5378 CHECK(try_catch.HasCaught());
5380 CHECK(!try_catch.HasCaught());
5384 TEST(TryCatchNativeReset) {
5385 v8::Isolate* isolate = CcTest::isolate();
5386 v8::HandleScope scope(isolate);
5387 v8::V8::Initialize();
5388 v8::TryCatch try_catch;
5389 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5390 templ->Set(v8_str("TryCatchNativeResetHelper"),
5391 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5392 LocalContext context(0, templ);
5393 CompileRun("TryCatchNativeResetHelper();");
5394 CHECK(!try_catch.HasCaught());
5398 THREADED_TEST(Equality) {
5399 LocalContext context;
5400 v8::Isolate* isolate = context->GetIsolate();
5401 v8::HandleScope scope(context->GetIsolate());
5402 // Check that equality works at all before relying on CHECK_EQ
5403 CHECK(v8_str("a")->Equals(v8_str("a")));
5404 CHECK(!v8_str("a")->Equals(v8_str("b")));
5406 CHECK(v8_str("a")->Equals(v8_str("a")));
5407 CHECK(!v8_str("a")->Equals(v8_str("b")));
5408 CHECK(v8_num(1)->Equals(v8_num(1)));
5409 CHECK(v8_num(1.00)->Equals(v8_num(1)));
5410 CHECK(!v8_num(1)->Equals(v8_num(2)));
5412 // Assume String is not internalized.
5413 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5414 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5415 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5416 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5417 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5418 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5419 Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
5420 CHECK(!not_a_number->StrictEquals(not_a_number));
5421 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5422 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5424 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5425 v8::Persistent<v8::Object> alias(isolate, obj);
5426 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5429 CHECK(v8_str("a")->SameValue(v8_str("a")));
5430 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5431 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5432 CHECK(v8_num(1)->SameValue(v8_num(1)));
5433 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5434 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5435 CHECK(not_a_number->SameValue(not_a_number));
5436 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5437 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5441 THREADED_TEST(MultiRun) {
5442 LocalContext context;
5443 v8::HandleScope scope(context->GetIsolate());
5444 Local<Script> script = v8_compile("x");
5445 for (int i = 0; i < 10; i++) script->Run();
5449 static void GetXValue(Local<String> name,
5450 const v8::PropertyCallbackInfo<v8::Value>& info) {
5451 ApiTestFuzzer::Fuzz();
5452 CHECK(info.Data()->Equals(v8_str("donut")));
5453 CHECK(name->Equals(v8_str("x")));
5454 info.GetReturnValue().Set(name);
5458 THREADED_TEST(SimplePropertyRead) {
5459 LocalContext context;
5460 v8::Isolate* isolate = context->GetIsolate();
5461 v8::HandleScope scope(isolate);
5462 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5463 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5464 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5465 Local<Script> script = v8_compile("obj.x");
5466 for (int i = 0; i < 10; i++) {
5467 Local<Value> result = script->Run();
5468 CHECK(result->Equals(v8_str("x")));
5473 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5474 LocalContext context;
5475 v8::Isolate* isolate = context->GetIsolate();
5476 v8::HandleScope scope(isolate);
5477 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5478 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5479 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5481 // Uses getOwnPropertyDescriptor to check the configurable status
5482 Local<Script> script_desc = v8_compile(
5483 "var prop = Object.getOwnPropertyDescriptor( "
5485 "prop.configurable;");
5486 Local<Value> result = script_desc->Run();
5487 CHECK_EQ(result->BooleanValue(), true);
5489 // Redefine get - but still configurable
5490 Local<Script> script_define = v8_compile(
5491 "var desc = { get: function(){return 42; },"
5492 " configurable: true };"
5493 "Object.defineProperty(obj, 'x', desc);"
5495 result = script_define->Run();
5496 CHECK(result->Equals(v8_num(42)));
5498 // Check that the accessor is still configurable
5499 result = script_desc->Run();
5500 CHECK_EQ(result->BooleanValue(), true);
5502 // Redefine to a non-configurable
5503 script_define = v8_compile(
5504 "var desc = { get: function(){return 43; },"
5505 " configurable: false };"
5506 "Object.defineProperty(obj, 'x', desc);"
5508 result = script_define->Run();
5509 CHECK(result->Equals(v8_num(43)));
5510 result = script_desc->Run();
5511 CHECK_EQ(result->BooleanValue(), false);
5513 // Make sure that it is not possible to redefine again
5514 v8::TryCatch try_catch;
5515 result = script_define->Run();
5516 CHECK(try_catch.HasCaught());
5517 String::Utf8Value exception_value(try_catch.Exception());
5519 strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5523 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5524 v8::Isolate* isolate = CcTest::isolate();
5525 v8::HandleScope scope(isolate);
5526 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5527 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5528 LocalContext context;
5529 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5531 Local<Script> script_desc = v8_compile(
5533 "Object.getOwnPropertyDescriptor( "
5535 "prop.configurable;");
5536 Local<Value> result = script_desc->Run();
5537 CHECK_EQ(result->BooleanValue(), true);
5539 Local<Script> script_define = v8_compile(
5540 "var desc = {get: function(){return 42; },"
5541 " configurable: true };"
5542 "Object.defineProperty(obj, 'x', desc);"
5544 result = script_define->Run();
5545 CHECK(result->Equals(v8_num(42)));
5548 result = script_desc->Run();
5549 CHECK_EQ(result->BooleanValue(), true);
5552 script_define = v8_compile(
5553 "var desc = {get: function(){return 43; },"
5554 " configurable: false };"
5555 "Object.defineProperty(obj, 'x', desc);"
5557 result = script_define->Run();
5558 CHECK(result->Equals(v8_num(43)));
5559 result = script_desc->Run();
5561 CHECK_EQ(result->BooleanValue(), false);
5563 v8::TryCatch try_catch;
5564 result = script_define->Run();
5565 CHECK(try_catch.HasCaught());
5566 String::Utf8Value exception_value(try_catch.Exception());
5568 strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5572 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5574 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5578 THREADED_TEST(DefineAPIAccessorOnObject) {
5579 v8::Isolate* isolate = CcTest::isolate();
5580 v8::HandleScope scope(isolate);
5581 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5582 LocalContext context;
5584 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5585 CompileRun("var obj2 = {};");
5587 CHECK(CompileRun("obj1.x")->IsUndefined());
5588 CHECK(CompileRun("obj2.x")->IsUndefined());
5590 CHECK(GetGlobalProperty(&context, "obj1")
5591 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5593 ExpectString("obj1.x", "x");
5594 CHECK(CompileRun("obj2.x")->IsUndefined());
5596 CHECK(GetGlobalProperty(&context, "obj2")
5597 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5599 ExpectString("obj1.x", "x");
5600 ExpectString("obj2.x", "x");
5602 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5603 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5606 "Object.defineProperty(obj1, 'x',"
5607 "{ get: function() { return 'y'; }, configurable: true })");
5609 ExpectString("obj1.x", "y");
5610 ExpectString("obj2.x", "x");
5613 "Object.defineProperty(obj2, 'x',"
5614 "{ get: function() { return 'y'; }, configurable: true })");
5616 ExpectString("obj1.x", "y");
5617 ExpectString("obj2.x", "y");
5619 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5620 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5622 CHECK(GetGlobalProperty(&context, "obj1")
5623 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5624 CHECK(GetGlobalProperty(&context, "obj2")
5625 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5627 ExpectString("obj1.x", "x");
5628 ExpectString("obj2.x", "x");
5630 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5631 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5633 // Define getters/setters, but now make them not configurable.
5635 "Object.defineProperty(obj1, 'x',"
5636 "{ get: function() { return 'z'; }, configurable: false })");
5638 "Object.defineProperty(obj2, 'x',"
5639 "{ get: function() { return 'z'; }, configurable: false })");
5641 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5642 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5644 ExpectString("obj1.x", "z");
5645 ExpectString("obj2.x", "z");
5647 CHECK(!GetGlobalProperty(&context, "obj1")
5648 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5649 CHECK(!GetGlobalProperty(&context, "obj2")
5650 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5652 ExpectString("obj1.x", "z");
5653 ExpectString("obj2.x", "z");
5657 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5658 v8::Isolate* isolate = CcTest::isolate();
5659 v8::HandleScope scope(isolate);
5660 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5661 LocalContext context;
5663 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5664 CompileRun("var obj2 = {};");
5666 CHECK(GetGlobalProperty(&context, "obj1")
5667 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"),
5668 v8::DEFAULT, v8::DontDelete));
5669 CHECK(GetGlobalProperty(&context, "obj2")
5670 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"),
5671 v8::DEFAULT, v8::DontDelete));
5673 ExpectString("obj1.x", "x");
5674 ExpectString("obj2.x", "x");
5676 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5677 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5679 CHECK(!GetGlobalProperty(&context, "obj1")
5680 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5681 CHECK(!GetGlobalProperty(&context, "obj2")
5682 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5685 v8::TryCatch try_catch;
5687 "Object.defineProperty(obj1, 'x',"
5688 "{get: function() { return 'func'; }})");
5689 CHECK(try_catch.HasCaught());
5690 String::Utf8Value exception_value(try_catch.Exception());
5692 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5695 v8::TryCatch try_catch;
5697 "Object.defineProperty(obj2, 'x',"
5698 "{get: function() { return 'func'; }})");
5699 CHECK(try_catch.HasCaught());
5700 String::Utf8Value exception_value(try_catch.Exception());
5702 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5707 static void Get239Value(Local<String> name,
5708 const v8::PropertyCallbackInfo<v8::Value>& info) {
5709 ApiTestFuzzer::Fuzz();
5710 CHECK(info.Data()->Equals(v8_str("donut")));
5711 CHECK(name->Equals(v8_str("239")));
5712 info.GetReturnValue().Set(name);
5716 THREADED_TEST(ElementAPIAccessor) {
5717 v8::Isolate* isolate = CcTest::isolate();
5718 v8::HandleScope scope(isolate);
5719 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5720 LocalContext context;
5722 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5723 CompileRun("var obj2 = {};");
5725 CHECK(GetGlobalProperty(&context, "obj1")
5726 ->SetAccessor(v8_str("239"), Get239Value, NULL, v8_str("donut")));
5727 CHECK(GetGlobalProperty(&context, "obj2")
5728 ->SetAccessor(v8_str("239"), Get239Value, NULL, v8_str("donut")));
5730 ExpectString("obj1[239]", "239");
5731 ExpectString("obj2[239]", "239");
5732 ExpectString("obj1['239']", "239");
5733 ExpectString("obj2['239']", "239");
5737 v8::Persistent<Value> xValue;
5740 static void SetXValue(Local<String> name, Local<Value> value,
5741 const v8::PropertyCallbackInfo<void>& info) {
5742 CHECK(value->Equals(v8_num(4)));
5743 CHECK(info.Data()->Equals(v8_str("donut")));
5744 CHECK(name->Equals(v8_str("x")));
5745 CHECK(xValue.IsEmpty());
5746 xValue.Reset(info.GetIsolate(), value);
5750 THREADED_TEST(SimplePropertyWrite) {
5751 v8::Isolate* isolate = CcTest::isolate();
5752 v8::HandleScope scope(isolate);
5753 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5754 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5755 LocalContext context;
5756 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5757 Local<Script> script = v8_compile("obj.x = 4");
5758 for (int i = 0; i < 10; i++) {
5759 CHECK(xValue.IsEmpty());
5761 CHECK(v8_num(4)->Equals(Local<Value>::New(CcTest::isolate(), xValue)));
5767 THREADED_TEST(SetterOnly) {
5768 v8::Isolate* isolate = CcTest::isolate();
5769 v8::HandleScope scope(isolate);
5770 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5771 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5772 LocalContext context;
5773 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5774 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5775 for (int i = 0; i < 10; i++) {
5776 CHECK(xValue.IsEmpty());
5778 CHECK(v8_num(4)->Equals(Local<Value>::New(CcTest::isolate(), xValue)));
5784 THREADED_TEST(NoAccessors) {
5785 v8::Isolate* isolate = CcTest::isolate();
5786 v8::HandleScope scope(isolate);
5787 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5788 templ->SetAccessor(v8_str("x"), static_cast<v8::AccessorGetterCallback>(NULL),
5789 NULL, v8_str("donut"));
5790 LocalContext context;
5791 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5792 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5793 for (int i = 0; i < 10; i++) {
5799 THREADED_TEST(MultiContexts) {
5800 v8::Isolate* isolate = CcTest::isolate();
5801 v8::HandleScope scope(isolate);
5802 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5803 templ->Set(v8_str("dummy"),
5804 v8::FunctionTemplate::New(isolate, DummyCallHandler));
5806 Local<String> password = v8_str("Password");
5808 // Create an environment
5809 LocalContext context0(0, templ);
5810 context0->SetSecurityToken(password);
5811 v8::Handle<v8::Object> global0 = context0->Global();
5812 global0->Set(v8_str("custom"), v8_num(1234));
5813 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5815 // Create an independent environment
5816 LocalContext context1(0, templ);
5817 context1->SetSecurityToken(password);
5818 v8::Handle<v8::Object> global1 = context1->Global();
5819 global1->Set(v8_str("custom"), v8_num(1234));
5820 CHECK(!global0->Equals(global1));
5821 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5822 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
5824 // Now create a new context with the old global
5825 LocalContext context2(0, templ, global1);
5826 context2->SetSecurityToken(password);
5827 v8::Handle<v8::Object> global2 = context2->Global();
5828 CHECK(global1->Equals(global2));
5829 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
5830 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
5834 THREADED_TEST(FunctionPrototypeAcrossContexts) {
5835 // Make sure that functions created by cloning boilerplates cannot
5836 // communicate through their __proto__ field.
5838 v8::HandleScope scope(CcTest::isolate());
5841 v8::Handle<v8::Object> global0 = env0->Global();
5842 v8::Handle<v8::Object> object0 =
5843 global0->Get(v8_str("Object")).As<v8::Object>();
5844 v8::Handle<v8::Object> tostring0 =
5845 object0->Get(v8_str("toString")).As<v8::Object>();
5846 v8::Handle<v8::Object> proto0 =
5847 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
5848 proto0->Set(v8_str("custom"), v8_num(1234));
5851 v8::Handle<v8::Object> global1 = env1->Global();
5852 v8::Handle<v8::Object> object1 =
5853 global1->Get(v8_str("Object")).As<v8::Object>();
5854 v8::Handle<v8::Object> tostring1 =
5855 object1->Get(v8_str("toString")).As<v8::Object>();
5856 v8::Handle<v8::Object> proto1 =
5857 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
5858 CHECK(!proto1->Has(v8_str("custom")));
5862 THREADED_TEST(Regress892105) {
5863 // Make sure that object and array literals created by cloning
5864 // boilerplates cannot communicate through their __proto__
5865 // field. This is rather difficult to check, but we try to add stuff
5866 // to Object.prototype and Array.prototype and create a new
5867 // environment. This should succeed.
5869 v8::HandleScope scope(CcTest::isolate());
5871 Local<String> source = v8_str(
5872 "Object.prototype.obj = 1234;"
5873 "Array.prototype.arr = 4567;"
5877 Local<Script> script0 = v8_compile(source);
5878 CHECK_EQ(8901.0, script0->Run()->NumberValue());
5881 Local<Script> script1 = v8_compile(source);
5882 CHECK_EQ(8901.0, script1->Run()->NumberValue());
5886 THREADED_TEST(UndetectableObject) {
5888 v8::HandleScope scope(env->GetIsolate());
5890 Local<v8::FunctionTemplate> desc =
5891 v8::FunctionTemplate::New(env->GetIsolate());
5892 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5894 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5895 env->Global()->Set(v8_str("undetectable"), obj);
5897 ExpectString("undetectable.toString()", "[object Object]");
5898 ExpectString("typeof undetectable", "undefined");
5899 ExpectString("typeof(undetectable)", "undefined");
5900 ExpectBoolean("typeof undetectable == 'undefined'", true);
5901 ExpectBoolean("typeof undetectable == 'object'", false);
5902 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
5903 ExpectBoolean("!undetectable", true);
5905 ExpectObject("true&&undetectable", obj);
5906 ExpectBoolean("false&&undetectable", false);
5907 ExpectBoolean("true||undetectable", true);
5908 ExpectObject("false||undetectable", obj);
5910 ExpectObject("undetectable&&true", obj);
5911 ExpectObject("undetectable&&false", obj);
5912 ExpectBoolean("undetectable||true", true);
5913 ExpectBoolean("undetectable||false", false);
5915 ExpectBoolean("undetectable==null", true);
5916 ExpectBoolean("null==undetectable", true);
5917 ExpectBoolean("undetectable==undefined", true);
5918 ExpectBoolean("undefined==undetectable", true);
5919 ExpectBoolean("undetectable==undetectable", true);
5922 ExpectBoolean("undetectable===null", false);
5923 ExpectBoolean("null===undetectable", false);
5924 ExpectBoolean("undetectable===undefined", false);
5925 ExpectBoolean("undefined===undetectable", false);
5926 ExpectBoolean("undetectable===undetectable", true);
5930 THREADED_TEST(VoidLiteral) {
5932 v8::Isolate* isolate = env->GetIsolate();
5933 v8::HandleScope scope(isolate);
5935 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
5936 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5938 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5939 env->Global()->Set(v8_str("undetectable"), obj);
5941 ExpectBoolean("undefined == void 0", true);
5942 ExpectBoolean("undetectable == void 0", true);
5943 ExpectBoolean("null == void 0", true);
5944 ExpectBoolean("undefined === void 0", true);
5945 ExpectBoolean("undetectable === void 0", false);
5946 ExpectBoolean("null === void 0", false);
5948 ExpectBoolean("void 0 == undefined", true);
5949 ExpectBoolean("void 0 == undetectable", true);
5950 ExpectBoolean("void 0 == null", true);
5951 ExpectBoolean("void 0 === undefined", true);
5952 ExpectBoolean("void 0 === undetectable", false);
5953 ExpectBoolean("void 0 === null", false);
5958 " return x === void 0;"
5960 " return e.toString();"
5963 "ReferenceError: x is not defined");
5967 " return void 0 === x;"
5969 " return e.toString();"
5972 "ReferenceError: x is not defined");
5976 THREADED_TEST(ExtensibleOnUndetectable) {
5978 v8::Isolate* isolate = env->GetIsolate();
5979 v8::HandleScope scope(isolate);
5981 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
5982 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5984 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5985 env->Global()->Set(v8_str("undetectable"), obj);
5987 Local<String> source = v8_str(
5988 "undetectable.x = 42;"
5991 Local<Script> script = v8_compile(source);
5993 CHECK(v8::Integer::New(isolate, 42)->Equals(script->Run()));
5995 ExpectBoolean("Object.isExtensible(undetectable)", true);
5997 source = v8_str("Object.preventExtensions(undetectable);");
5998 script = v8_compile(source);
6000 ExpectBoolean("Object.isExtensible(undetectable)", false);
6002 source = v8_str("undetectable.y = 2000;");
6003 script = v8_compile(source);
6005 ExpectBoolean("undetectable.y == undefined", true);
6009 // The point of this test is type checking. We run it only so compilers
6010 // don't complain about an unused function.
6011 TEST(PersistentHandles) {
6013 v8::Isolate* isolate = CcTest::isolate();
6014 v8::HandleScope scope(isolate);
6015 Local<String> str = v8_str("foo");
6016 v8::Persistent<String> p_str(isolate, str);
6018 Local<Script> scr = v8_compile("");
6019 v8::Persistent<Script> p_scr(isolate, scr);
6021 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6022 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6027 static void HandleLogDelegator(
6028 const v8::FunctionCallbackInfo<v8::Value>& args) {
6029 ApiTestFuzzer::Fuzz();
6033 THREADED_TEST(GlobalObjectTemplate) {
6034 v8::Isolate* isolate = CcTest::isolate();
6035 v8::HandleScope handle_scope(isolate);
6036 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6037 global_template->Set(v8_str("JSNI_Log"),
6038 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6039 v8::Local<Context> context = Context::New(isolate, 0, global_template);
6040 Context::Scope context_scope(context);
6041 CompileRun("JSNI_Log('LOG')");
6045 static const char* kSimpleExtensionSource =
6051 TEST(SimpleExtensions) {
6052 v8::HandleScope handle_scope(CcTest::isolate());
6053 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
6054 const char* extension_names[] = {"simpletest"};
6055 v8::ExtensionConfiguration extensions(1, extension_names);
6056 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6057 Context::Scope lock(context);
6058 v8::Handle<Value> result = CompileRun("Foo()");
6059 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6063 static const char* kStackTraceFromExtensionSource =
6065 " throw new Error();"
6072 TEST(StackTraceInExtension) {
6073 v8::HandleScope handle_scope(CcTest::isolate());
6074 v8::RegisterExtension(
6075 new Extension("stacktracetest", kStackTraceFromExtensionSource));
6076 const char* extension_names[] = {"stacktracetest"};
6077 v8::ExtensionConfiguration extensions(1, extension_names);
6078 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6079 Context::Scope lock(context);
6081 "function user() { bar(); }"
6083 "try{ user(); } catch (e) { error = e; }");
6084 CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
6085 CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
6086 CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
6090 TEST(NullExtensions) {
6091 v8::HandleScope handle_scope(CcTest::isolate());
6092 v8::RegisterExtension(new Extension("nulltest", NULL));
6093 const char* extension_names[] = {"nulltest"};
6094 v8::ExtensionConfiguration extensions(1, extension_names);
6095 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6096 Context::Scope lock(context);
6097 v8::Handle<Value> result = CompileRun("1+3");
6098 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6102 static const char* kEmbeddedExtensionSource =
6103 "function Ret54321(){return 54321;}~~@@$"
6104 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
6105 static const int kEmbeddedExtensionSourceValidLen = 34;
6108 TEST(ExtensionMissingSourceLength) {
6109 v8::HandleScope handle_scope(CcTest::isolate());
6110 v8::RegisterExtension(
6111 new Extension("srclentest_fail", kEmbeddedExtensionSource));
6112 const char* extension_names[] = {"srclentest_fail"};
6113 v8::ExtensionConfiguration extensions(1, extension_names);
6114 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6115 CHECK(0 == *context);
6119 TEST(ExtensionWithSourceLength) {
6120 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
6121 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
6122 v8::HandleScope handle_scope(CcTest::isolate());
6123 i::ScopedVector<char> extension_name(32);
6124 i::SNPrintF(extension_name, "ext #%d", source_len);
6125 v8::RegisterExtension(new Extension(
6126 extension_name.start(), kEmbeddedExtensionSource, 0, 0, source_len));
6127 const char* extension_names[1] = {extension_name.start()};
6128 v8::ExtensionConfiguration extensions(1, extension_names);
6129 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6130 if (source_len == kEmbeddedExtensionSourceValidLen) {
6131 Context::Scope lock(context);
6132 v8::Handle<Value> result = CompileRun("Ret54321()");
6133 CHECK(v8::Integer::New(CcTest::isolate(), 54321)->Equals(result));
6135 // Anything but exactly the right length should fail to compile.
6136 CHECK(0 == *context);
6142 static const char* kEvalExtensionSource1 =
6143 "function UseEval1() {"
6145 " return eval('x');"
6149 static const char* kEvalExtensionSource2 =
6153 " return eval('x');"
6155 " this.UseEval2 = e;"
6159 TEST(UseEvalFromExtension) {
6160 v8::HandleScope handle_scope(CcTest::isolate());
6161 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
6162 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
6163 const char* extension_names[] = {"evaltest1", "evaltest2"};
6164 v8::ExtensionConfiguration extensions(2, extension_names);
6165 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6166 Context::Scope lock(context);
6167 v8::Handle<Value> result = CompileRun("UseEval1()");
6168 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6169 result = CompileRun("UseEval2()");
6170 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6174 static const char* kWithExtensionSource1 =
6175 "function UseWith1() {"
6177 " with({x:87}) { return x; }"
6181 static const char* kWithExtensionSource2 =
6185 " with ({x:87}) { return x; }"
6187 " this.UseWith2 = e;"
6191 TEST(UseWithFromExtension) {
6192 v8::HandleScope handle_scope(CcTest::isolate());
6193 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
6194 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
6195 const char* extension_names[] = {"withtest1", "withtest2"};
6196 v8::ExtensionConfiguration extensions(2, extension_names);
6197 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6198 Context::Scope lock(context);
6199 v8::Handle<Value> result = CompileRun("UseWith1()");
6200 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 87)));
6201 result = CompileRun("UseWith2()");
6202 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 87)));
6206 TEST(AutoExtensions) {
6207 v8::HandleScope handle_scope(CcTest::isolate());
6208 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
6209 extension->set_auto_enable(true);
6210 v8::RegisterExtension(extension);
6211 v8::Handle<Context> context = Context::New(CcTest::isolate());
6212 Context::Scope lock(context);
6213 v8::Handle<Value> result = CompileRun("Foo()");
6214 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
6218 static const char* kSyntaxErrorInExtensionSource = "[";
6221 // Test that a syntax error in an extension does not cause a fatal
6222 // error but results in an empty context.
6223 TEST(SyntaxErrorExtensions) {
6224 v8::HandleScope handle_scope(CcTest::isolate());
6225 v8::RegisterExtension(
6226 new Extension("syntaxerror", kSyntaxErrorInExtensionSource));
6227 const char* extension_names[] = {"syntaxerror"};
6228 v8::ExtensionConfiguration extensions(1, extension_names);
6229 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6230 CHECK(context.IsEmpty());
6234 static const char* kExceptionInExtensionSource = "throw 42";
6237 // Test that an exception when installing an extension does not cause
6238 // a fatal error but results in an empty context.
6239 TEST(ExceptionExtensions) {
6240 v8::HandleScope handle_scope(CcTest::isolate());
6241 v8::RegisterExtension(
6242 new Extension("exception", kExceptionInExtensionSource));
6243 const char* extension_names[] = {"exception"};
6244 v8::ExtensionConfiguration extensions(1, extension_names);
6245 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6246 CHECK(context.IsEmpty());
6250 static const char* kNativeCallInExtensionSource =
6251 "function call_runtime_last_index_of(x) {"
6252 " return %StringLastIndexOf(x, 'bob', 10);"
6256 static const char* kNativeCallTest =
6257 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6259 // Test that a native runtime calls are supported in extensions.
6260 TEST(NativeCallInExtensions) {
6261 v8::HandleScope handle_scope(CcTest::isolate());
6262 v8::RegisterExtension(
6263 new Extension("nativecall", kNativeCallInExtensionSource));
6264 const char* extension_names[] = {"nativecall"};
6265 v8::ExtensionConfiguration extensions(1, extension_names);
6266 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6267 Context::Scope lock(context);
6268 v8::Handle<Value> result = CompileRun(kNativeCallTest);
6269 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 3)));
6273 class NativeFunctionExtension : public Extension {
6275 NativeFunctionExtension(const char* name, const char* source,
6276 v8::FunctionCallback fun = &Echo)
6277 : Extension(name, source), function_(fun) {}
6279 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6280 v8::Isolate* isolate, v8::Handle<v8::String> name) {
6281 return v8::FunctionTemplate::New(isolate, function_);
6284 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6285 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6289 v8::FunctionCallback function_;
6293 TEST(NativeFunctionDeclaration) {
6294 v8::HandleScope handle_scope(CcTest::isolate());
6295 const char* name = "nativedecl";
6296 v8::RegisterExtension(
6297 new NativeFunctionExtension(name, "native function foo();"));
6298 const char* extension_names[] = {name};
6299 v8::ExtensionConfiguration extensions(1, extension_names);
6300 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6301 Context::Scope lock(context);
6302 v8::Handle<Value> result = CompileRun("foo(42);");
6303 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6307 TEST(NativeFunctionDeclarationError) {
6308 v8::HandleScope handle_scope(CcTest::isolate());
6309 const char* name = "nativedeclerr";
6310 // Syntax error in extension code.
6311 v8::RegisterExtension(
6312 new NativeFunctionExtension(name, "native\nfunction foo();"));
6313 const char* extension_names[] = {name};
6314 v8::ExtensionConfiguration extensions(1, extension_names);
6315 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6316 CHECK(context.IsEmpty());
6320 TEST(NativeFunctionDeclarationErrorEscape) {
6321 v8::HandleScope handle_scope(CcTest::isolate());
6322 const char* name = "nativedeclerresc";
6323 // Syntax error in extension code - escape code in "native" means that
6324 // it's not treated as a keyword.
6325 v8::RegisterExtension(
6326 new NativeFunctionExtension(name, "nativ\\u0065 function foo();"));
6327 const char* extension_names[] = {name};
6328 v8::ExtensionConfiguration extensions(1, extension_names);
6329 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6330 CHECK(context.IsEmpty());
6334 static void CheckDependencies(const char* name, const char* expected) {
6335 v8::HandleScope handle_scope(CcTest::isolate());
6336 v8::ExtensionConfiguration config(1, &name);
6337 LocalContext context(&config);
6338 CHECK(String::NewFromUtf8(CcTest::isolate(), expected)
6339 ->Equals(context->Global()->Get(v8_str("loaded"))));
6350 THREADED_TEST(ExtensionDependency) {
6351 static const char* kEDeps[] = {"D"};
6352 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6353 static const char* kDDeps[] = {"B", "C"};
6354 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6355 static const char* kBCDeps[] = {"A"};
6356 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6357 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6358 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6359 CheckDependencies("A", "undefinedA");
6360 CheckDependencies("B", "undefinedAB");
6361 CheckDependencies("C", "undefinedAC");
6362 CheckDependencies("D", "undefinedABCD");
6363 CheckDependencies("E", "undefinedABCDE");
6364 v8::HandleScope handle_scope(CcTest::isolate());
6365 static const char* exts[2] = {"C", "E"};
6366 v8::ExtensionConfiguration config(2, exts);
6367 LocalContext context(&config);
6368 CHECK(v8_str("undefinedACBDE")
6369 ->Equals(context->Global()->Get(v8_str("loaded"))));
6373 static const char* kExtensionTestScript =
6374 "native function A();"
6375 "native function B();"
6376 "native function C();"
6378 " if (i == 0) return A();"
6379 " if (i == 1) return B();"
6380 " if (i == 2) return C();"
6384 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6385 ApiTestFuzzer::Fuzz();
6386 if (args.IsConstructCall()) {
6387 args.This()->Set(v8_str("data"), args.Data());
6388 args.GetReturnValue().SetNull();
6391 args.GetReturnValue().Set(args.Data());
6395 class FunctionExtension : public Extension {
6397 FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
6398 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6399 v8::Isolate* isolate, v8::Handle<String> name);
6403 static int lookup_count = 0;
6404 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6405 v8::Isolate* isolate, v8::Handle<String> name) {
6407 if (name->Equals(v8_str("A"))) {
6408 return v8::FunctionTemplate::New(isolate, CallFun,
6409 v8::Integer::New(isolate, 8));
6410 } else if (name->Equals(v8_str("B"))) {
6411 return v8::FunctionTemplate::New(isolate, CallFun,
6412 v8::Integer::New(isolate, 7));
6413 } else if (name->Equals(v8_str("C"))) {
6414 return v8::FunctionTemplate::New(isolate, CallFun,
6415 v8::Integer::New(isolate, 6));
6417 return v8::Handle<v8::FunctionTemplate>();
6422 THREADED_TEST(FunctionLookup) {
6423 v8::RegisterExtension(new FunctionExtension());
6424 v8::HandleScope handle_scope(CcTest::isolate());
6425 static const char* exts[1] = {"functiontest"};
6426 v8::ExtensionConfiguration config(1, exts);
6427 LocalContext context(&config);
6428 CHECK_EQ(3, lookup_count);
6429 CHECK(v8::Integer::New(CcTest::isolate(), 8)->Equals(CompileRun("Foo(0)")));
6430 CHECK(v8::Integer::New(CcTest::isolate(), 7)->Equals(CompileRun("Foo(1)")));
6431 CHECK(v8::Integer::New(CcTest::isolate(), 6)->Equals(CompileRun("Foo(2)")));
6435 THREADED_TEST(NativeFunctionConstructCall) {
6436 v8::RegisterExtension(new FunctionExtension());
6437 v8::HandleScope handle_scope(CcTest::isolate());
6438 static const char* exts[1] = {"functiontest"};
6439 v8::ExtensionConfiguration config(1, exts);
6440 LocalContext context(&config);
6441 for (int i = 0; i < 10; i++) {
6442 // Run a few times to ensure that allocation of objects doesn't
6443 // change behavior of a constructor function.
6444 CHECK(v8::Integer::New(CcTest::isolate(), 8)
6445 ->Equals(CompileRun("(new A()).data")));
6446 CHECK(v8::Integer::New(CcTest::isolate(), 7)
6447 ->Equals(CompileRun("(new B()).data")));
6448 CHECK(v8::Integer::New(CcTest::isolate(), 6)
6449 ->Equals(CompileRun("(new C()).data")));
6454 static const char* last_location;
6455 static const char* last_message;
6456 void StoringErrorCallback(const char* location, const char* message) {
6457 if (last_location == NULL) {
6458 last_location = location;
6459 last_message = message;
6464 // ErrorReporting creates a circular extensions configuration and
6465 // tests that the fatal error handler gets called. This renders V8
6466 // unusable and therefore this test cannot be run in parallel.
6467 TEST(ErrorReporting) {
6468 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
6469 static const char* aDeps[] = {"B"};
6470 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
6471 static const char* bDeps[] = {"A"};
6472 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
6473 last_location = NULL;
6474 v8::ExtensionConfiguration config(1, bDeps);
6475 v8::Handle<Context> context = Context::New(CcTest::isolate(), &config);
6476 CHECK(context.IsEmpty());
6477 CHECK(last_location);
6481 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
6482 v8::Handle<Value> data) {
6483 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
6484 CHECK(v8::Undefined(CcTest::isolate())
6485 ->Equals(message->GetScriptOrigin().ResourceName()));
6486 message->GetLineNumber();
6487 message->GetSourceLine();
6491 THREADED_TEST(ErrorWithMissingScriptInfo) {
6492 LocalContext context;
6493 v8::HandleScope scope(context->GetIsolate());
6494 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
6495 CompileRun("throw Error()");
6496 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
6500 struct FlagAndPersistent {
6502 v8::Global<v8::Object> handle;
6506 static void SetFlag(const v8::WeakCallbackInfo<FlagAndPersistent>& data) {
6507 data.GetParameter()->flag = true;
6508 data.GetParameter()->handle.Reset();
6512 static void IndependentWeakHandle(bool global_gc, bool interlinked) {
6513 v8::Isolate* iso = CcTest::isolate();
6514 v8::HandleScope scope(iso);
6515 v8::Handle<Context> context = Context::New(iso);
6516 Context::Scope context_scope(context);
6518 FlagAndPersistent object_a, object_b;
6520 intptr_t big_heap_size;
6523 v8::HandleScope handle_scope(iso);
6524 Local<Object> a(v8::Object::New(iso));
6525 Local<Object> b(v8::Object::New(iso));
6526 object_a.handle.Reset(iso, a);
6527 object_b.handle.Reset(iso, b);
6529 a->Set(v8_str("x"), b);
6530 b->Set(v8_str("x"), a);
6533 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
6535 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6537 // We are relying on this creating a big flag array and reserving the space
6539 v8::Handle<Value> big_array = CompileRun("new Array(50000)");
6540 a->Set(v8_str("y"), big_array);
6541 big_heap_size = CcTest::heap()->SizeOfObjects();
6544 object_a.flag = false;
6545 object_b.flag = false;
6546 object_a.handle.SetWeak(&object_a, &SetFlag,
6547 v8::WeakCallbackType::kParameter);
6548 object_b.handle.SetWeak(&object_b, &SetFlag,
6549 v8::WeakCallbackType::kParameter);
6550 CHECK(!object_b.handle.IsIndependent());
6551 object_a.handle.MarkIndependent();
6552 object_b.handle.MarkIndependent();
6553 CHECK(object_b.handle.IsIndependent());
6555 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
6557 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6559 // A single GC should be enough to reclaim the memory, since we are using
6561 CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
6562 CHECK(object_a.flag);
6563 CHECK(object_b.flag);
6567 THREADED_TEST(IndependentWeakHandle) {
6568 IndependentWeakHandle(false, false);
6569 IndependentWeakHandle(false, true);
6570 IndependentWeakHandle(true, false);
6571 IndependentWeakHandle(true, true);
6577 explicit Trivial(int x) : x_(x) {}
6579 int x() { return x_; }
6580 void set_x(int x) { x_ = x; }
6589 Trivial2(int x, int y) : y_(y), x_(x) {}
6591 int x() { return x_; }
6592 void set_x(int x) { x_ = x; }
6594 int y() { return y_; }
6595 void set_y(int y) { y_ = y; }
6603 void CheckInternalFields(
6604 const v8::WeakCallbackInfo<v8::Persistent<v8::Object>>& data) {
6605 v8::Persistent<v8::Object>* handle = data.GetParameter();
6607 Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField1());
6608 Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField2());
6609 CHECK_EQ(42, t1->x());
6610 CHECK_EQ(103, t2->x());
6612 t2->set_x(33550336);
6616 void InternalFieldCallback(bool global_gc) {
6618 v8::Isolate* isolate = env->GetIsolate();
6619 v8::HandleScope scope(isolate);
6621 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
6622 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
6625 instance_templ->SetInternalFieldCount(2);
6627 v8::HandleScope scope(isolate);
6628 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
6629 v8::Persistent<v8::Object> handle(isolate, obj);
6630 CHECK_EQ(2, obj->InternalFieldCount());
6631 CHECK(obj->GetInternalField(0)->IsUndefined());
6632 t1 = new Trivial(42);
6633 t2 = new Trivial2(103, 9);
6635 obj->SetAlignedPointerInInternalField(0, t1);
6636 t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
6637 CHECK_EQ(42, t1->x());
6639 obj->SetAlignedPointerInInternalField(1, t2);
6641 reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
6642 CHECK_EQ(103, t2->x());
6644 handle.SetWeak<v8::Persistent<v8::Object>>(
6645 &handle, CheckInternalFields, v8::WeakCallbackType::kInternalFields);
6647 handle.MarkIndependent();
6651 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
6653 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6656 CHECK_EQ(1729, t1->x());
6657 CHECK_EQ(33550336, t2->x());
6664 THREADED_TEST(InternalFieldCallback) {
6665 InternalFieldCallback(false);
6666 InternalFieldCallback(true);
6670 static void ResetUseValueAndSetFlag(
6671 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6672 // Blink will reset the handle, and then use the other handle, so they
6673 // can't use the same backing slot.
6674 data.GetParameter()->handle.Reset();
6675 data.GetValue()->IsBoolean(); // Make sure the handle still works.
6676 data.GetParameter()->flag = true;
6680 static void ResetWeakHandle(bool global_gc) {
6681 v8::Isolate* iso = CcTest::isolate();
6682 v8::HandleScope scope(iso);
6683 v8::Handle<Context> context = Context::New(iso);
6684 Context::Scope context_scope(context);
6686 FlagAndPersistent object_a, object_b;
6689 v8::HandleScope handle_scope(iso);
6690 Local<Object> a(v8::Object::New(iso));
6691 Local<Object> b(v8::Object::New(iso));
6692 object_a.handle.Reset(iso, a);
6693 object_b.handle.Reset(iso, b);
6695 CcTest::heap()->CollectAllGarbage(
6696 TestHeap::Heap::kAbortIncrementalMarkingMask);
6698 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6702 object_a.flag = false;
6703 object_b.flag = false;
6704 object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
6705 object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
6707 object_a.handle.MarkIndependent();
6708 object_b.handle.MarkIndependent();
6709 CHECK(object_b.handle.IsIndependent());
6712 CcTest::heap()->CollectAllGarbage(
6713 TestHeap::Heap::kAbortIncrementalMarkingMask);
6715 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6717 CHECK(object_a.flag);
6718 CHECK(object_b.flag);
6722 THREADED_TEST(ResetWeakHandle) {
6723 ResetWeakHandle(false);
6724 ResetWeakHandle(true);
6728 static void InvokeScavenge() { CcTest::heap()->CollectGarbage(i::NEW_SPACE); }
6731 static void InvokeMarkSweep() {
6732 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
6736 static void ForceScavenge(
6737 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6738 data.GetParameter()->handle.Reset();
6739 data.GetParameter()->flag = true;
6744 static void ForceMarkSweep(
6745 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6746 data.GetParameter()->handle.Reset();
6747 data.GetParameter()->flag = true;
6752 THREADED_TEST(GCFromWeakCallbacks) {
6753 v8::Isolate* isolate = CcTest::isolate();
6754 v8::HandleScope scope(isolate);
6755 v8::Handle<Context> context = Context::New(isolate);
6756 Context::Scope context_scope(context);
6758 static const int kNumberOfGCTypes = 2;
6759 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
6761 Callback gc_forcing_callback[kNumberOfGCTypes] =
6762 {&ForceScavenge, &ForceMarkSweep};
6764 typedef void (*GCInvoker)();
6765 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
6767 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
6768 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
6769 FlagAndPersistent object;
6771 v8::HandleScope handle_scope(isolate);
6772 object.handle.Reset(isolate, v8::Object::New(isolate));
6774 object.flag = false;
6775 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
6776 object.handle.MarkIndependent();
6777 invoke_gc[outer_gc]();
6784 static void RevivingCallback(
6785 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6786 data.GetParameter()->handle.ClearWeak();
6787 data.GetParameter()->flag = true;
6791 THREADED_TEST(IndependentHandleRevival) {
6792 v8::Isolate* isolate = CcTest::isolate();
6793 v8::HandleScope scope(isolate);
6794 v8::Handle<Context> context = Context::New(isolate);
6795 Context::Scope context_scope(context);
6797 FlagAndPersistent object;
6799 v8::HandleScope handle_scope(isolate);
6800 v8::Local<v8::Object> o = v8::Object::New(isolate);
6801 object.handle.Reset(isolate, o);
6802 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
6803 v8::Local<String> y_str = v8_str("y");
6804 o->Set(y_str, y_str);
6806 object.flag = false;
6807 object.handle.SetWeak(&object, &RevivingCallback);
6808 object.handle.MarkIndependent();
6809 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6811 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
6813 v8::HandleScope handle_scope(isolate);
6814 v8::Local<v8::Object> o =
6815 v8::Local<v8::Object>::New(isolate, object.handle);
6816 v8::Local<String> y_str = v8_str("y");
6817 CHECK(v8::Integer::New(isolate, 1)->Equals(o->Get(v8_str("x"))));
6818 CHECK(o->Get(y_str)->Equals(y_str));
6823 v8::Handle<Function> args_fun;
6826 static void ArgumentsTestCallback(
6827 const v8::FunctionCallbackInfo<v8::Value>& args) {
6828 ApiTestFuzzer::Fuzz();
6829 v8::Isolate* isolate = args.GetIsolate();
6830 CHECK(args_fun->Equals(args.Callee()));
6831 CHECK_EQ(3, args.Length());
6832 CHECK(v8::Integer::New(isolate, 1)->Equals(args[0]));
6833 CHECK(v8::Integer::New(isolate, 2)->Equals(args[1]));
6834 CHECK(v8::Integer::New(isolate, 3)->Equals(args[2]));
6835 CHECK(v8::Undefined(isolate)->Equals(args[3]));
6836 v8::HandleScope scope(args.GetIsolate());
6837 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
6841 THREADED_TEST(Arguments) {
6842 v8::Isolate* isolate = CcTest::isolate();
6843 v8::HandleScope scope(isolate);
6844 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
6845 global->Set(v8_str("f"),
6846 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
6847 LocalContext context(NULL, global);
6848 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
6849 v8_compile("f(1, 2, 3)")->Run();
6853 static int p_getter_count;
6854 static int p_getter_count2;
6857 static void PGetter(Local<String> name,
6858 const v8::PropertyCallbackInfo<v8::Value>& info) {
6859 ApiTestFuzzer::Fuzz();
6861 v8::Handle<v8::Object> global =
6862 info.GetIsolate()->GetCurrentContext()->Global();
6863 CHECK(info.Holder()->Equals(global->Get(v8_str("o1"))));
6864 if (name->Equals(v8_str("p1"))) {
6865 CHECK(info.This()->Equals(global->Get(v8_str("o1"))));
6866 } else if (name->Equals(v8_str("p2"))) {
6867 CHECK(info.This()->Equals(global->Get(v8_str("o2"))));
6868 } else if (name->Equals(v8_str("p3"))) {
6869 CHECK(info.This()->Equals(global->Get(v8_str("o3"))));
6870 } else if (name->Equals(v8_str("p4"))) {
6871 CHECK(info.This()->Equals(global->Get(v8_str("o4"))));
6876 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
6877 ApiTestFuzzer::Fuzz();
6878 LocalContext context;
6879 context->Global()->Set(v8_str("o1"), obj->NewInstance());
6881 "o1.__proto__ = { };"
6882 "var o2 = { __proto__: o1 };"
6883 "var o3 = { __proto__: o2 };"
6884 "var o4 = { __proto__: o3 };"
6885 "for (var i = 0; i < 10; i++) o4.p4;"
6886 "for (var i = 0; i < 10; i++) o3.p3;"
6887 "for (var i = 0; i < 10; i++) o2.p2;"
6888 "for (var i = 0; i < 10; i++) o1.p1;");
6892 static void PGetter2(Local<Name> name,
6893 const v8::PropertyCallbackInfo<v8::Value>& info) {
6894 ApiTestFuzzer::Fuzz();
6896 v8::Handle<v8::Object> global =
6897 info.GetIsolate()->GetCurrentContext()->Global();
6898 CHECK(info.Holder()->Equals(global->Get(v8_str("o1"))));
6899 if (name->Equals(v8_str("p1"))) {
6900 CHECK(info.This()->Equals(global->Get(v8_str("o1"))));
6901 } else if (name->Equals(v8_str("p2"))) {
6902 CHECK(info.This()->Equals(global->Get(v8_str("o2"))));
6903 } else if (name->Equals(v8_str("p3"))) {
6904 CHECK(info.This()->Equals(global->Get(v8_str("o3"))));
6905 } else if (name->Equals(v8_str("p4"))) {
6906 CHECK(info.This()->Equals(global->Get(v8_str("o4"))));
6911 THREADED_TEST(GetterHolders) {
6912 v8::Isolate* isolate = CcTest::isolate();
6913 v8::HandleScope scope(isolate);
6914 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
6915 obj->SetAccessor(v8_str("p1"), PGetter);
6916 obj->SetAccessor(v8_str("p2"), PGetter);
6917 obj->SetAccessor(v8_str("p3"), PGetter);
6918 obj->SetAccessor(v8_str("p4"), PGetter);
6921 CHECK_EQ(40, p_getter_count);
6925 THREADED_TEST(PreInterceptorHolders) {
6926 v8::Isolate* isolate = CcTest::isolate();
6927 v8::HandleScope scope(isolate);
6928 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
6929 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
6930 p_getter_count2 = 0;
6932 CHECK_EQ(40, p_getter_count2);
6936 THREADED_TEST(ObjectInstantiation) {
6937 v8::Isolate* isolate = CcTest::isolate();
6938 v8::HandleScope scope(isolate);
6939 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
6940 templ->SetAccessor(v8_str("t"), PGetter2);
6941 LocalContext context;
6942 context->Global()->Set(v8_str("o"), templ->NewInstance());
6943 for (int i = 0; i < 100; i++) {
6944 v8::HandleScope inner_scope(CcTest::isolate());
6945 v8::Handle<v8::Object> obj = templ->NewInstance();
6946 CHECK(!obj->Equals(context->Global()->Get(v8_str("o"))));
6947 context->Global()->Set(v8_str("o2"), obj);
6948 v8::Handle<Value> value =
6949 CompileRun("o.__proto__ === o2.__proto__");
6950 CHECK(v8::True(isolate)->Equals(value));
6951 context->Global()->Set(v8_str("o"), obj);
6956 static int StrCmp16(uint16_t* a, uint16_t* b) {
6958 if (*a == 0 && *b == 0) return 0;
6959 if (*a != *b) return 0 + *a - *b;
6966 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
6968 if (n-- == 0) return 0;
6969 if (*a == 0 && *b == 0) return 0;
6970 if (*a != *b) return 0 + *a - *b;
6977 int GetUtf8Length(Handle<String> str) {
6978 int len = str->Utf8Length();
6980 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
6981 i::String::Flatten(istr);
6982 len = str->Utf8Length();
6988 THREADED_TEST(StringWrite) {
6989 LocalContext context;
6990 v8::HandleScope scope(context->GetIsolate());
6991 v8::Handle<String> str = v8_str("abcde");
6992 // abc<Icelandic eth><Unicode snowman>.
6993 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
6994 v8::Handle<String> str3 = v8::String::NewFromUtf8(
6995 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
6996 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
6997 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
6998 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
6999 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
7000 // single lead surrogate
7001 uint16_t lead[1] = { 0xd800 };
7002 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
7003 context->GetIsolate(), lead, v8::String::kNormalString, 1);
7004 // single trail surrogate
7005 uint16_t trail[1] = { 0xdc00 };
7006 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
7007 context->GetIsolate(), trail, v8::String::kNormalString, 1);
7009 uint16_t pair[2] = { 0xd800, 0xdc00 };
7010 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
7011 context->GetIsolate(), pair, v8::String::kNormalString, 2);
7012 const int kStride = 4; // Must match stride in for loops in JS below.
7015 "for (var i = 0; i < 0xd800; i += 4) {"
7016 " left = left + String.fromCharCode(i);"
7020 "for (var i = 0; i < 0xd800; i += 4) {"
7021 " right = String.fromCharCode(i) + right;"
7023 v8::Handle<v8::Object> global = context->Global();
7024 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
7025 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
7027 CHECK_EQ(5, str2->Length());
7028 CHECK_EQ(0xd800 / kStride, left_tree->Length());
7029 CHECK_EQ(0xd800 / kStride, right_tree->Length());
7032 char utf8buf[0xd800 * 3];
7037 memset(utf8buf, 0x1, 1000);
7038 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7040 CHECK_EQ(5, charlen);
7041 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7043 memset(utf8buf, 0x1, 1000);
7044 len = str2->WriteUtf8(utf8buf, 8, &charlen);
7046 CHECK_EQ(5, charlen);
7047 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
7049 memset(utf8buf, 0x1, 1000);
7050 len = str2->WriteUtf8(utf8buf, 7, &charlen);
7052 CHECK_EQ(4, charlen);
7053 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7055 memset(utf8buf, 0x1, 1000);
7056 len = str2->WriteUtf8(utf8buf, 6, &charlen);
7058 CHECK_EQ(4, charlen);
7059 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7061 memset(utf8buf, 0x1, 1000);
7062 len = str2->WriteUtf8(utf8buf, 5, &charlen);
7064 CHECK_EQ(4, charlen);
7065 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
7067 memset(utf8buf, 0x1, 1000);
7068 len = str2->WriteUtf8(utf8buf, 4, &charlen);
7070 CHECK_EQ(3, charlen);
7071 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7073 memset(utf8buf, 0x1, 1000);
7074 len = str2->WriteUtf8(utf8buf, 3, &charlen);
7076 CHECK_EQ(3, charlen);
7077 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
7079 memset(utf8buf, 0x1, 1000);
7080 len = str2->WriteUtf8(utf8buf, 2, &charlen);
7082 CHECK_EQ(2, charlen);
7083 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
7085 // allow orphan surrogates by default
7086 memset(utf8buf, 0x1, 1000);
7087 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
7089 CHECK_EQ(8, charlen);
7090 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
7092 // replace orphan surrogates with unicode replacement character
7093 memset(utf8buf, 0x1, 1000);
7094 len = orphans_str->WriteUtf8(utf8buf,
7097 String::REPLACE_INVALID_UTF8);
7099 CHECK_EQ(8, charlen);
7100 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
7102 // replace single lead surrogate with unicode replacement character
7103 memset(utf8buf, 0x1, 1000);
7104 len = lead_str->WriteUtf8(utf8buf,
7107 String::REPLACE_INVALID_UTF8);
7109 CHECK_EQ(1, charlen);
7110 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7112 // replace single trail surrogate with unicode replacement character
7113 memset(utf8buf, 0x1, 1000);
7114 len = trail_str->WriteUtf8(utf8buf,
7117 String::REPLACE_INVALID_UTF8);
7119 CHECK_EQ(1, charlen);
7120 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
7122 // do not replace / write anything if surrogate pair does not fit the buffer
7124 memset(utf8buf, 0x1, 1000);
7125 len = pair_str->WriteUtf8(utf8buf,
7128 String::REPLACE_INVALID_UTF8);
7130 CHECK_EQ(0, charlen);
7132 memset(utf8buf, 0x1, sizeof(utf8buf));
7133 len = GetUtf8Length(left_tree);
7135 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
7136 CHECK_EQ(utf8_expected, len);
7137 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7138 CHECK_EQ(utf8_expected, len);
7139 CHECK_EQ(0xd800 / kStride, charlen);
7140 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
7141 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
7142 CHECK_EQ(0xc0 - kStride,
7143 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
7144 CHECK_EQ(1, utf8buf[utf8_expected]);
7146 memset(utf8buf, 0x1, sizeof(utf8buf));
7147 len = GetUtf8Length(right_tree);
7148 CHECK_EQ(utf8_expected, len);
7149 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
7150 CHECK_EQ(utf8_expected, len);
7151 CHECK_EQ(0xd800 / kStride, charlen);
7152 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
7153 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
7154 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
7155 CHECK_EQ(1, utf8buf[utf8_expected]);
7157 memset(buf, 0x1, sizeof(buf));
7158 memset(wbuf, 0x1, sizeof(wbuf));
7159 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7161 len = str->Write(wbuf);
7163 CHECK_EQ(0, strcmp("abcde", buf));
7164 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7165 CHECK_EQ(0, StrCmp16(answer1, wbuf));
7167 memset(buf, 0x1, sizeof(buf));
7168 memset(wbuf, 0x1, sizeof(wbuf));
7169 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
7171 len = str->Write(wbuf, 0, 4);
7173 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
7174 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
7175 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
7177 memset(buf, 0x1, sizeof(buf));
7178 memset(wbuf, 0x1, sizeof(wbuf));
7179 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
7181 len = str->Write(wbuf, 0, 5);
7183 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
7184 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
7185 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
7187 memset(buf, 0x1, sizeof(buf));
7188 memset(wbuf, 0x1, sizeof(wbuf));
7189 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
7191 len = str->Write(wbuf, 0, 6);
7193 CHECK_EQ(0, strcmp("abcde", buf));
7194 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7195 CHECK_EQ(0, StrCmp16(answer4, wbuf));
7197 memset(buf, 0x1, sizeof(buf));
7198 memset(wbuf, 0x1, sizeof(wbuf));
7199 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
7201 len = str->Write(wbuf, 4, -1);
7203 CHECK_EQ(0, strcmp("e", buf));
7204 uint16_t answer5[] = {'e', '\0'};
7205 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7207 memset(buf, 0x1, sizeof(buf));
7208 memset(wbuf, 0x1, sizeof(wbuf));
7209 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
7211 len = str->Write(wbuf, 4, 6);
7213 CHECK_EQ(0, strcmp("e", buf));
7214 CHECK_EQ(0, StrCmp16(answer5, wbuf));
7216 memset(buf, 0x1, sizeof(buf));
7217 memset(wbuf, 0x1, sizeof(wbuf));
7218 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
7220 len = str->Write(wbuf, 4, 1);
7222 CHECK_EQ(0, strncmp("e\1", buf, 2));
7223 uint16_t answer6[] = {'e', 0x101};
7224 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
7226 memset(buf, 0x1, sizeof(buf));
7227 memset(wbuf, 0x1, sizeof(wbuf));
7228 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
7230 len = str->Write(wbuf, 3, 1);
7232 CHECK_EQ(0, strncmp("d\1", buf, 2));
7233 uint16_t answer7[] = {'d', 0x101};
7234 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7236 memset(wbuf, 0x1, sizeof(wbuf));
7238 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7240 CHECK_EQ('X', wbuf[5]);
7241 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7242 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7243 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7244 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7246 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7248 memset(buf, 0x1, sizeof(buf));
7250 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7253 String::NO_NULL_TERMINATION);
7255 CHECK_EQ('X', buf[5]);
7256 CHECK_EQ(0, strncmp("abcde", buf, 5));
7257 CHECK_NE(0, strcmp("abcde", buf));
7259 CHECK_EQ(0, strcmp("abcde", buf));
7261 memset(utf8buf, 0x1, sizeof(utf8buf));
7263 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7264 String::NO_NULL_TERMINATION);
7266 CHECK_EQ('X', utf8buf[8]);
7267 CHECK_EQ(5, charlen);
7268 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7269 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7271 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7273 memset(utf8buf, 0x1, sizeof(utf8buf));
7275 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7276 String::NO_NULL_TERMINATION);
7278 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7279 CHECK_EQ(5, charlen);
7281 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7283 memset(buf, 0x1, sizeof(buf));
7284 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7286 CHECK_EQ(0, strcmp("abc", buf));
7287 CHECK_EQ(0, buf[3]);
7288 CHECK_EQ(0, strcmp("def", buf + 4));
7290 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7291 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7292 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7296 static void Utf16Helper(
7297 LocalContext& context, // NOLINT
7299 const char* lengths_name,
7301 Local<v8::Array> a =
7302 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7303 Local<v8::Array> alens =
7304 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7305 for (int i = 0; i < len; i++) {
7306 Local<v8::String> string =
7307 Local<v8::String>::Cast(a->Get(i));
7308 Local<v8::Number> expected_len =
7309 Local<v8::Number>::Cast(alens->Get(i));
7310 int length = GetUtf8Length(string);
7311 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7316 static uint16_t StringGet(Handle<String> str, int index) {
7317 i::Handle<i::String> istring =
7318 v8::Utils::OpenHandle(String::Cast(*str));
7319 return istring->Get(index);
7323 static void WriteUtf8Helper(
7324 LocalContext& context, // NOLINT
7326 const char* lengths_name,
7328 Local<v8::Array> b =
7329 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7330 Local<v8::Array> alens =
7331 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7334 for (int i = 0; i < len; i++) {
7335 Local<v8::String> string =
7336 Local<v8::String>::Cast(b->Get(i));
7337 Local<v8::Number> expected_len =
7338 Local<v8::Number>::Cast(alens->Get(i));
7339 int utf8_length = static_cast<int>(expected_len->Value());
7340 for (int j = utf8_length + 1; j >= 0; j--) {
7341 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7342 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7345 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7347 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7348 CHECK_GE(utf8_length + 1, utf8_written);
7349 CHECK_GE(utf8_length, utf8_written2);
7350 for (int k = 0; k < utf8_written2; k++) {
7351 CHECK_EQ(buffer[k], buffer2[k]);
7353 CHECK(nchars * 3 >= utf8_written - 1);
7354 CHECK(nchars <= utf8_written);
7355 if (j == utf8_length + 1) {
7356 CHECK_EQ(utf8_written2, utf8_length);
7357 CHECK_EQ(utf8_written2 + 1, utf8_written);
7359 CHECK_EQ(buffer[utf8_written], 42);
7360 if (j > utf8_length) {
7361 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7362 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7363 Handle<String> roundtrip = v8_str(buffer);
7364 CHECK(roundtrip->Equals(string));
7366 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7368 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7370 uint16_t trail = StringGet(string, nchars - 1);
7371 uint16_t lead = StringGet(string, nchars - 2);
7372 if (((lead & 0xfc00) == 0xd800) &&
7373 ((trail & 0xfc00) == 0xdc00)) {
7374 unsigned u1 = buffer2[utf8_written2 - 4];
7375 unsigned u2 = buffer2[utf8_written2 - 3];
7376 unsigned u3 = buffer2[utf8_written2 - 2];
7377 unsigned u4 = buffer2[utf8_written2 - 1];
7378 CHECK_EQ((u1 & 0xf8), 0xf0u);
7379 CHECK_EQ((u2 & 0xc0), 0x80u);
7380 CHECK_EQ((u3 & 0xc0), 0x80u);
7381 CHECK_EQ((u4 & 0xc0), 0x80u);
7382 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7383 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7384 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7385 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7386 CHECK_EQ((u1 & 0x3), c >> 18);
7394 THREADED_TEST(Utf16) {
7395 LocalContext context;
7396 v8::HandleScope scope(context->GetIsolate());
7398 "var pad = '01234567890123456789';"
7400 "var plens = [20, 3, 3];"
7401 "p.push('01234567890123456789');"
7402 "var lead = 0xd800;"
7403 "var trail = 0xdc00;"
7404 "p.push(String.fromCharCode(0xd800));"
7405 "p.push(String.fromCharCode(0xdc00));"
7410 "for (var i = 0; i < 3; i++) {"
7411 " p[1] = String.fromCharCode(lead++);"
7412 " for (var j = 0; j < 3; j++) {"
7413 " p[2] = String.fromCharCode(trail++);"
7414 " a.push(p[i] + p[j]);"
7415 " b.push(p[i] + p[j]);"
7416 " c.push(p[i] + p[j]);"
7417 " alens.push(plens[i] + plens[j]);"
7420 "alens[5] -= 2;" // Here the surrogate pairs match up.
7425 "for (var m = 0; m < 9; m++) {"
7426 " for (var n = 0; n < 9; n++) {"
7427 " a2.push(a[m] + a[n]);"
7428 " b2.push(b[m] + b[n]);"
7429 " var newc = 'x' + c[m] + c[n] + 'y';"
7430 " c2.push(newc.substring(1, newc.length - 1));"
7431 " var utf = alens[m] + alens[n];" // And here.
7432 // The 'n's that start with 0xdc.. are 6-8
7433 // The 'm's that end with 0xd8.. are 1, 4 and 7
7434 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
7435 " a2lens.push(utf);"
7438 Utf16Helper(context, "a", "alens", 9);
7439 Utf16Helper(context, "a2", "a2lens", 81);
7440 WriteUtf8Helper(context, "b", "alens", 9);
7441 WriteUtf8Helper(context, "b2", "a2lens", 81);
7442 WriteUtf8Helper(context, "c2", "a2lens", 81);
7446 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7447 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7448 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7449 return *is1 == *is2;
7452 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
7454 Handle<String> symbol1 =
7455 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
7456 Handle<String> symbol2 =
7457 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
7458 CHECK(SameSymbol(symbol1, symbol2));
7462 THREADED_TEST(Utf16Symbol) {
7463 LocalContext context;
7464 v8::HandleScope scope(context->GetIsolate());
7466 Handle<String> symbol1 = v8::String::NewFromUtf8(
7467 context->GetIsolate(), "abc", v8::String::kInternalizedString);
7468 Handle<String> symbol2 = v8::String::NewFromUtf8(
7469 context->GetIsolate(), "abc", v8::String::kInternalizedString);
7470 CHECK(SameSymbol(symbol1, symbol2));
7472 SameSymbolHelper(context->GetIsolate(),
7473 "\360\220\220\205", // 4 byte encoding.
7474 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
7475 SameSymbolHelper(context->GetIsolate(),
7476 "\355\240\201\355\260\206", // 2 3-byte surrogates.
7477 "\360\220\220\206"); // 4 byte encoding.
7478 SameSymbolHelper(context->GetIsolate(),
7479 "x\360\220\220\205", // 4 byte encoding.
7480 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
7481 SameSymbolHelper(context->GetIsolate(),
7482 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
7483 "x\360\220\220\206"); // 4 byte encoding.
7485 "var sym0 = 'benedictus';"
7486 "var sym0b = 'S\303\270ren';"
7487 "var sym1 = '\355\240\201\355\260\207';"
7488 "var sym2 = '\360\220\220\210';"
7489 "var sym3 = 'x\355\240\201\355\260\207';"
7490 "var sym4 = 'x\360\220\220\210';"
7491 "if (sym1.length != 2) throw sym1;"
7492 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
7493 "if (sym2.length != 2) throw sym2;"
7494 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
7495 "if (sym3.length != 3) throw sym3;"
7496 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
7497 "if (sym4.length != 3) throw sym4;"
7498 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
7499 Handle<String> sym0 = v8::String::NewFromUtf8(
7500 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
7501 Handle<String> sym0b = v8::String::NewFromUtf8(
7502 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
7503 Handle<String> sym1 =
7504 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
7505 v8::String::kInternalizedString);
7506 Handle<String> sym2 =
7507 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
7508 v8::String::kInternalizedString);
7509 Handle<String> sym3 = v8::String::NewFromUtf8(
7510 context->GetIsolate(), "x\355\240\201\355\260\207",
7511 v8::String::kInternalizedString);
7512 Handle<String> sym4 =
7513 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
7514 v8::String::kInternalizedString);
7515 v8::Local<v8::Object> global = context->Global();
7516 Local<Value> s0 = global->Get(v8_str("sym0"));
7517 Local<Value> s0b = global->Get(v8_str("sym0b"));
7518 Local<Value> s1 = global->Get(v8_str("sym1"));
7519 Local<Value> s2 = global->Get(v8_str("sym2"));
7520 Local<Value> s3 = global->Get(v8_str("sym3"));
7521 Local<Value> s4 = global->Get(v8_str("sym4"));
7522 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
7523 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
7524 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
7525 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
7526 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
7527 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
7531 THREADED_TEST(ToArrayIndex) {
7532 LocalContext context;
7533 v8::Isolate* isolate = context->GetIsolate();
7534 v8::HandleScope scope(isolate);
7536 v8::Handle<String> str = v8_str("42");
7537 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
7538 CHECK(!index.IsEmpty());
7539 CHECK_EQ(42.0, index->Uint32Value());
7540 str = v8_str("42asdf");
7541 index = str->ToArrayIndex();
7542 CHECK(index.IsEmpty());
7543 str = v8_str("-42");
7544 index = str->ToArrayIndex();
7545 CHECK(index.IsEmpty());
7546 str = v8_str("4294967295");
7547 index = str->ToArrayIndex();
7548 CHECK(!index.IsEmpty());
7549 CHECK_EQ(4294967295.0, index->Uint32Value());
7550 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
7551 index = num->ToArrayIndex();
7552 CHECK(!index.IsEmpty());
7553 CHECK_EQ(1.0, index->Uint32Value());
7554 num = v8::Number::New(isolate, -1);
7555 index = num->ToArrayIndex();
7556 CHECK(index.IsEmpty());
7557 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
7558 index = obj->ToArrayIndex();
7559 CHECK(index.IsEmpty());
7563 THREADED_TEST(ErrorConstruction) {
7564 LocalContext context;
7565 v8::HandleScope scope(context->GetIsolate());
7567 v8::Handle<String> foo = v8_str("foo");
7568 v8::Handle<String> message = v8_str("message");
7569 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
7570 CHECK(range_error->IsObject());
7571 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
7572 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
7573 CHECK(reference_error->IsObject());
7574 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
7575 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
7576 CHECK(syntax_error->IsObject());
7577 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
7578 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
7579 CHECK(type_error->IsObject());
7580 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
7581 v8::Handle<Value> error = v8::Exception::Error(foo);
7582 CHECK(error->IsObject());
7583 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7587 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
7588 ApiTestFuzzer::Fuzz();
7589 v8::Handle<String> foo = v8_str("foo");
7590 v8::Handle<String> message = v8_str("message");
7591 v8::Handle<Value> error = v8::Exception::Error(foo);
7592 CHECK(error->IsObject());
7593 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7594 info.GetIsolate()->ThrowException(error);
7595 info.GetReturnValue().SetUndefined();
7599 THREADED_TEST(ExceptionCreateMessage) {
7600 LocalContext context;
7601 v8::HandleScope scope(context->GetIsolate());
7602 v8::Handle<String> foo_str = v8_str("foo");
7603 v8::Handle<String> message_str = v8_str("message");
7605 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
7607 Local<v8::FunctionTemplate> fun =
7608 v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
7609 v8::Local<v8::Object> global = context->Global();
7610 global->Set(v8_str("throwV8Exception"), fun->GetFunction());
7615 " throwV8Exception();\n"
7618 CHECK(try_catch.HasCaught());
7620 v8::Handle<v8::Value> error = try_catch.Exception();
7621 CHECK(error->IsObject());
7622 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
7624 v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
7625 CHECK(!message.IsEmpty());
7626 CHECK_EQ(2, message->GetLineNumber());
7627 CHECK_EQ(2, message->GetStartColumn());
7629 v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
7630 CHECK(!stackTrace.IsEmpty());
7631 CHECK_EQ(2, stackTrace->GetFrameCount());
7633 stackTrace = v8::Exception::GetStackTrace(error);
7634 CHECK(!stackTrace.IsEmpty());
7635 CHECK_EQ(2, stackTrace->GetFrameCount());
7637 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
7639 // Now check message location when SetCaptureStackTraceForUncaughtExceptions
7645 " return throwV8Exception();\n"
7648 CHECK(try_catch.HasCaught());
7650 error = try_catch.Exception();
7651 CHECK(error->IsObject());
7652 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
7654 message = v8::Exception::CreateMessage(error);
7655 CHECK(!message.IsEmpty());
7656 CHECK_EQ(2, message->GetLineNumber());
7657 CHECK_EQ(9, message->GetStartColumn());
7659 // Should be empty stack trace.
7660 stackTrace = message->GetStackTrace();
7661 CHECK(stackTrace.IsEmpty());
7662 CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
7666 static void YGetter(Local<String> name,
7667 const v8::PropertyCallbackInfo<v8::Value>& info) {
7668 ApiTestFuzzer::Fuzz();
7669 info.GetReturnValue().Set(v8_num(10));
7673 static void YSetter(Local<String> name,
7675 const v8::PropertyCallbackInfo<void>& info) {
7676 Local<Object> this_obj = Local<Object>::Cast(info.This());
7677 if (this_obj->Has(name)) this_obj->Delete(name);
7678 this_obj->Set(name, value);
7682 THREADED_TEST(DeleteAccessor) {
7683 v8::Isolate* isolate = CcTest::isolate();
7684 v8::HandleScope scope(isolate);
7685 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7686 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
7687 LocalContext context;
7688 v8::Handle<v8::Object> holder = obj->NewInstance();
7689 context->Global()->Set(v8_str("holder"), holder);
7690 v8::Handle<Value> result = CompileRun(
7691 "holder.y = 11; holder.y = 12; holder.y");
7692 CHECK_EQ(12u, result->Uint32Value());
7696 THREADED_TEST(TypeSwitch) {
7697 v8::Isolate* isolate = CcTest::isolate();
7698 v8::HandleScope scope(isolate);
7699 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
7700 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
7701 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
7702 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
7703 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
7704 LocalContext context;
7705 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
7706 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
7707 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
7708 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
7709 for (int i = 0; i < 10; i++) {
7710 CHECK_EQ(0, type_switch->match(obj0));
7711 CHECK_EQ(1, type_switch->match(obj1));
7712 CHECK_EQ(2, type_switch->match(obj2));
7713 CHECK_EQ(3, type_switch->match(obj3));
7714 CHECK_EQ(3, type_switch->match(obj3));
7715 CHECK_EQ(2, type_switch->match(obj2));
7716 CHECK_EQ(1, type_switch->match(obj1));
7717 CHECK_EQ(0, type_switch->match(obj0));
7722 static int trouble_nesting = 0;
7723 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7724 ApiTestFuzzer::Fuzz();
7727 // Call a JS function that throws an uncaught exception.
7728 Local<v8::Object> arg_this =
7729 args.GetIsolate()->GetCurrentContext()->Global();
7730 Local<Value> trouble_callee = (trouble_nesting == 3) ?
7731 arg_this->Get(v8_str("trouble_callee")) :
7732 arg_this->Get(v8_str("trouble_caller"));
7733 CHECK(trouble_callee->IsFunction());
7734 args.GetReturnValue().Set(
7735 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
7739 static int report_count = 0;
7740 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
7741 v8::Handle<Value>) {
7746 // Counts uncaught exceptions, but other tests running in parallel
7747 // also have uncaught exceptions.
7748 TEST(ApiUncaughtException) {
7751 v8::Isolate* isolate = env->GetIsolate();
7752 v8::HandleScope scope(isolate);
7753 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7755 Local<v8::FunctionTemplate> fun =
7756 v8::FunctionTemplate::New(isolate, TroubleCallback);
7757 v8::Local<v8::Object> global = env->Global();
7758 global->Set(v8_str("trouble"), fun->GetFunction());
7761 "function trouble_callee() {"
7765 "function trouble_caller() {"
7768 Local<Value> trouble = global->Get(v8_str("trouble"));
7769 CHECK(trouble->IsFunction());
7770 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
7771 CHECK(trouble_callee->IsFunction());
7772 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
7773 CHECK(trouble_caller->IsFunction());
7774 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
7775 CHECK_EQ(1, report_count);
7776 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7780 TEST(ApiUncaughtExceptionInObjectObserve) {
7781 v8::internal::FLAG_stack_size = 150;
7784 v8::Isolate* isolate = env->GetIsolate();
7785 v8::HandleScope scope(isolate);
7786 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7789 "var observe_count = 0;"
7790 "function observer1() { ++observe_count; };"
7791 "function observer2() { ++observe_count; };"
7792 "function observer_throws() { throw new Error(); };"
7793 "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
7794 "Object.observe(obj, observer_throws.bind());"
7795 "Object.observe(obj, observer1);"
7796 "Object.observe(obj, stack_overflow);"
7797 "Object.observe(obj, observer2);"
7798 "Object.observe(obj, observer_throws.bind());"
7799 "obj.foo = 'bar';");
7800 CHECK_EQ(3, report_count);
7801 ExpectInt32("observe_count", 2);
7802 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7806 static const char* script_resource_name = "ExceptionInNativeScript.js";
7807 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
7808 v8::Handle<Value>) {
7809 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
7810 CHECK(!name_val.IsEmpty() && name_val->IsString());
7811 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
7812 CHECK_EQ(0, strcmp(script_resource_name, *name));
7813 CHECK_EQ(3, message->GetLineNumber());
7814 v8::String::Utf8Value source_line(message->GetSourceLine());
7815 CHECK_EQ(0, strcmp(" new o.foo();", *source_line));
7819 TEST(ExceptionInNativeScript) {
7821 v8::Isolate* isolate = env->GetIsolate();
7822 v8::HandleScope scope(isolate);
7823 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
7825 Local<v8::FunctionTemplate> fun =
7826 v8::FunctionTemplate::New(isolate, TroubleCallback);
7827 v8::Local<v8::Object> global = env->Global();
7828 global->Set(v8_str("trouble"), fun->GetFunction());
7830 CompileRunWithOrigin(
7831 "function trouble() {\n"
7835 script_resource_name);
7836 Local<Value> trouble = global->Get(v8_str("trouble"));
7837 CHECK(trouble->IsFunction());
7838 Function::Cast(*trouble)->Call(global, 0, NULL);
7839 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
7843 TEST(CompilationErrorUsingTryCatchHandler) {
7845 v8::HandleScope scope(env->GetIsolate());
7846 v8::TryCatch try_catch;
7847 v8_compile("This doesn't &*&@#$&*^ compile.");
7848 CHECK(*try_catch.Exception());
7849 CHECK(try_catch.HasCaught());
7853 TEST(TryCatchFinallyUsingTryCatchHandler) {
7855 v8::HandleScope scope(env->GetIsolate());
7856 v8::TryCatch try_catch;
7857 CompileRun("try { throw ''; } catch (e) {}");
7858 CHECK(!try_catch.HasCaught());
7859 CompileRun("try { throw ''; } finally {}");
7860 CHECK(try_catch.HasCaught());
7864 "try { throw ''; } finally { return; }"
7866 CHECK(!try_catch.HasCaught());
7869 " { try { throw ''; } finally { throw 0; }"
7871 CHECK(try_catch.HasCaught());
7875 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
7876 v8::HandleScope scope(args.GetIsolate());
7877 CompileRun(args[0]->ToString(args.GetIsolate()));
7881 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
7882 v8::Isolate* isolate = CcTest::isolate();
7883 v8::HandleScope scope(isolate);
7884 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7885 templ->Set(v8_str("CEvaluate"),
7886 v8::FunctionTemplate::New(isolate, CEvaluate));
7887 LocalContext context(0, templ);
7888 v8::TryCatch try_catch;
7890 " CEvaluate('throw 1;');"
7893 CHECK(try_catch.HasCaught());
7894 CHECK(!try_catch.Message().IsEmpty());
7895 String::Utf8Value exception_value(try_catch.Exception());
7896 CHECK_EQ(0, strcmp(*exception_value, "1"));
7899 " CEvaluate('throw 1;');"
7903 CHECK(try_catch.HasCaught());
7904 CHECK(!try_catch.Message().IsEmpty());
7905 String::Utf8Value finally_exception_value(try_catch.Exception());
7906 CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
7910 // For use within the TestSecurityHandler() test.
7911 static bool g_security_callback_result = false;
7912 static bool SecurityTestCallback(Local<v8::Object> global, Local<Value> name,
7913 v8::AccessType type, Local<Value> data) {
7915 return g_security_callback_result;
7919 // SecurityHandler can't be run twice
7920 TEST(SecurityHandler) {
7921 v8::Isolate* isolate = CcTest::isolate();
7922 v8::HandleScope scope0(isolate);
7923 v8::Handle<v8::ObjectTemplate> global_template =
7924 v8::ObjectTemplate::New(isolate);
7925 global_template->SetAccessCheckCallbacks(SecurityTestCallback, NULL);
7926 // Create an environment
7927 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
7930 v8::Handle<v8::Object> global0 = context0->Global();
7931 v8::Handle<Script> script0 = v8_compile("foo = 111");
7933 global0->Set(v8_str("0"), v8_num(999));
7934 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
7935 CHECK_EQ(111, foo0->Int32Value());
7936 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
7937 CHECK_EQ(999, z0->Int32Value());
7939 // Create another environment, should fail security checks.
7940 v8::HandleScope scope1(isolate);
7942 v8::Handle<Context> context1 =
7943 Context::New(isolate, NULL, global_template);
7946 v8::Handle<v8::Object> global1 = context1->Global();
7947 global1->Set(v8_str("othercontext"), global0);
7948 // This set will fail the security check.
7949 v8::Handle<Script> script1 =
7950 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
7952 g_security_callback_result = true;
7953 // This read will pass the security check.
7954 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
7955 CHECK_EQ(111, foo1->Int32Value());
7956 // This read will pass the security check.
7957 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
7958 CHECK_EQ(999, z1->Int32Value());
7960 // Create another environment, should pass security checks.
7962 v8::HandleScope scope2(isolate);
7963 LocalContext context2;
7964 v8::Handle<v8::Object> global2 = context2->Global();
7965 global2->Set(v8_str("othercontext"), global0);
7966 v8::Handle<Script> script2 =
7967 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
7969 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
7970 CHECK_EQ(333, foo2->Int32Value());
7971 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
7972 CHECK_EQ(888, z2->Int32Value());
7980 THREADED_TEST(SecurityChecks) {
7982 v8::HandleScope handle_scope(env1->GetIsolate());
7983 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7985 Local<Value> foo = v8_str("foo");
7986 Local<Value> bar = v8_str("bar");
7988 // Set to the same domain.
7989 env1->SetSecurityToken(foo);
7991 // Create a function in env1.
7992 CompileRun("spy=function(){return spy;}");
7993 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
7994 CHECK(spy->IsFunction());
7996 // Create another function accessing global objects.
7997 CompileRun("spy2=function(){return new this.Array();}");
7998 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
7999 CHECK(spy2->IsFunction());
8001 // Switch to env2 in the same domain and invoke spy on env2.
8003 env2->SetSecurityToken(foo);
8005 Context::Scope scope_env2(env2);
8006 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
8007 CHECK(result->IsFunction());
8011 env2->SetSecurityToken(bar);
8012 Context::Scope scope_env2(env2);
8014 // Call cross_domain_call, it should throw an exception
8015 v8::TryCatch try_catch;
8016 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
8017 CHECK(try_catch.HasCaught());
8022 // Regression test case for issue 1183439.
8023 THREADED_TEST(SecurityChecksForPrototypeChain) {
8024 LocalContext current;
8025 v8::HandleScope scope(current->GetIsolate());
8026 v8::Handle<Context> other = Context::New(current->GetIsolate());
8028 // Change context to be able to get to the Object function in the
8029 // other context without hitting the security checks.
8030 v8::Local<Value> other_object;
8031 { Context::Scope scope(other);
8032 other_object = other->Global()->Get(v8_str("Object"));
8033 other->Global()->Set(v8_num(42), v8_num(87));
8036 current->Global()->Set(v8_str("other"), other->Global());
8037 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
8039 // Make sure the security check fails here and we get an undefined
8040 // result instead of getting the Object function. Repeat in a loop
8041 // to make sure to exercise the IC code.
8042 v8::Local<Script> access_other0 = v8_compile("other.Object");
8043 v8::Local<Script> access_other1 = v8_compile("other[42]");
8044 for (int i = 0; i < 5; i++) {
8045 CHECK(access_other0->Run().IsEmpty());
8046 CHECK(access_other1->Run().IsEmpty());
8049 // Create an object that has 'other' in its prototype chain and make
8050 // sure we cannot access the Object function indirectly through
8051 // that. Repeat in a loop to make sure to exercise the IC code.
8052 v8_compile("function F() { };"
8053 "F.prototype = other;"
8054 "var f = new F();")->Run();
8055 v8::Local<Script> access_f0 = v8_compile("f.Object");
8056 v8::Local<Script> access_f1 = v8_compile("f[42]");
8057 for (int j = 0; j < 5; j++) {
8058 CHECK(access_f0->Run().IsEmpty());
8059 CHECK(access_f1->Run().IsEmpty());
8062 // Now it gets hairy: Set the prototype for the other global object
8063 // to be the current global object. The prototype chain for 'f' now
8064 // goes through 'other' but ends up in the current global object.
8065 { Context::Scope scope(other);
8066 other->Global()->Set(v8_str("__proto__"), current->Global());
8068 // Set a named and an index property on the current global
8069 // object. To force the lookup to go through the other global object,
8070 // the properties must not exist in the other global object.
8071 current->Global()->Set(v8_str("foo"), v8_num(100));
8072 current->Global()->Set(v8_num(99), v8_num(101));
8073 // Try to read the properties from f and make sure that the access
8074 // gets stopped by the security checks on the other global object.
8075 Local<Script> access_f2 = v8_compile("f.foo");
8076 Local<Script> access_f3 = v8_compile("f[99]");
8077 for (int k = 0; k < 5; k++) {
8078 CHECK(access_f2->Run().IsEmpty());
8079 CHECK(access_f3->Run().IsEmpty());
8084 static bool security_check_with_gc_called;
8086 static bool SecurityTestCallbackWithGC(Local<v8::Object> global,
8087 Local<v8::Value> name,
8088 v8::AccessType type, Local<Value> data) {
8089 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8090 security_check_with_gc_called = true;
8095 TEST(SecurityTestGCAllowed) {
8096 v8::Isolate* isolate = CcTest::isolate();
8097 v8::HandleScope handle_scope(isolate);
8098 v8::Handle<v8::ObjectTemplate> object_template =
8099 v8::ObjectTemplate::New(isolate);
8100 object_template->SetAccessCheckCallbacks(SecurityTestCallbackWithGC, NULL);
8102 v8::Handle<Context> context = Context::New(isolate);
8103 v8::Context::Scope context_scope(context);
8105 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
8107 security_check_with_gc_called = false;
8108 CompileRun("obj[0] = new String(1002);");
8109 CHECK(security_check_with_gc_called);
8111 security_check_with_gc_called = false;
8112 CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
8113 CHECK(security_check_with_gc_called);
8117 THREADED_TEST(CrossDomainDelete) {
8119 v8::HandleScope handle_scope(env1->GetIsolate());
8120 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8122 Local<Value> foo = v8_str("foo");
8123 Local<Value> bar = v8_str("bar");
8125 // Set to the same domain.
8126 env1->SetSecurityToken(foo);
8127 env2->SetSecurityToken(foo);
8129 env1->Global()->Set(v8_str("prop"), v8_num(3));
8130 env2->Global()->Set(v8_str("env1"), env1->Global());
8132 // Change env2 to a different domain and delete env1.prop.
8133 env2->SetSecurityToken(bar);
8135 Context::Scope scope_env2(env2);
8136 Local<Value> result =
8137 CompileRun("delete env1.prop");
8138 CHECK(result.IsEmpty());
8141 // Check that env1.prop still exists.
8142 Local<Value> v = env1->Global()->Get(v8_str("prop"));
8143 CHECK(v->IsNumber());
8144 CHECK_EQ(3, v->Int32Value());
8148 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
8150 v8::HandleScope handle_scope(env1->GetIsolate());
8151 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8153 Local<Value> foo = v8_str("foo");
8154 Local<Value> bar = v8_str("bar");
8156 // Set to the same domain.
8157 env1->SetSecurityToken(foo);
8158 env2->SetSecurityToken(foo);
8160 env1->Global()->Set(v8_str("prop"), v8_num(3));
8161 env2->Global()->Set(v8_str("env1"), env1->Global());
8163 // env1.prop is enumerable in env2.
8164 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
8166 Context::Scope scope_env2(env2);
8167 Local<Value> result = CompileRun(test);
8168 CHECK(result->IsTrue());
8171 // Change env2 to a different domain and test again.
8172 env2->SetSecurityToken(bar);
8174 Context::Scope scope_env2(env2);
8175 Local<Value> result = CompileRun(test);
8176 CHECK(result.IsEmpty());
8181 THREADED_TEST(CrossDomainForIn) {
8183 v8::HandleScope handle_scope(env1->GetIsolate());
8184 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8186 Local<Value> foo = v8_str("foo");
8187 Local<Value> bar = v8_str("bar");
8189 // Set to the same domain.
8190 env1->SetSecurityToken(foo);
8191 env2->SetSecurityToken(foo);
8193 env1->Global()->Set(v8_str("prop"), v8_num(3));
8194 env2->Global()->Set(v8_str("env1"), env1->Global());
8196 // Change env2 to a different domain and set env1's global object
8197 // as the __proto__ of an object in env2 and enumerate properties
8198 // in for-in. It shouldn't enumerate properties on env1's global
8200 env2->SetSecurityToken(bar);
8202 Context::Scope scope_env2(env2);
8203 Local<Value> result = CompileRun(
8205 " var obj = { '__proto__': env1 };"
8207 " for (var p in obj) {"
8208 " if (p == 'prop') return false;"
8215 CHECK(result->IsTrue());
8220 TEST(ContextDetachGlobal) {
8222 v8::HandleScope handle_scope(env1->GetIsolate());
8223 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8225 Local<v8::Object> global1 = env1->Global();
8227 Local<Value> foo = v8_str("foo");
8229 // Set to the same domain.
8230 env1->SetSecurityToken(foo);
8231 env2->SetSecurityToken(foo);
8236 // Create a function in env2 and add a reference to it in env1.
8237 Local<v8::Object> global2 = env2->Global();
8238 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8239 CompileRun("function getProp() {return prop;}");
8241 env1->Global()->Set(v8_str("getProp"),
8242 global2->Get(v8_str("getProp")));
8244 // Detach env2's global, and reuse the global object of env2
8246 env2->DetachGlobal();
8248 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8250 v8::Handle<v8::ObjectTemplate>(),
8252 env3->SetSecurityToken(v8_str("bar"));
8255 Local<v8::Object> global3 = env3->Global();
8256 CHECK(global2->Equals(global3));
8257 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8258 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8259 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8260 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8263 // Call getProp in env1, and it should return the value 1
8265 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8266 CHECK(get_prop->IsFunction());
8267 v8::TryCatch try_catch;
8268 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8269 CHECK(!try_catch.HasCaught());
8270 CHECK_EQ(1, r->Int32Value());
8273 // Check that env3 is not accessible from env1
8275 Local<Value> r = global3->Get(v8_str("prop2"));
8281 TEST(DetachGlobal) {
8283 v8::HandleScope scope(env1->GetIsolate());
8285 // Create second environment.
8286 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8288 Local<Value> foo = v8_str("foo");
8290 // Set same security token for env1 and env2.
8291 env1->SetSecurityToken(foo);
8292 env2->SetSecurityToken(foo);
8294 // Create a property on the global object in env2.
8296 v8::Context::Scope scope(env2);
8297 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8300 // Create a reference to env2 global from env1 global.
8301 env1->Global()->Set(v8_str("other"), env2->Global());
8303 // Check that we have access to other.p in env2 from env1.
8304 Local<Value> result = CompileRun("other.p");
8305 CHECK(result->IsInt32());
8306 CHECK_EQ(42, result->Int32Value());
8308 // Hold on to global from env2 and detach global from env2.
8309 Local<v8::Object> global2 = env2->Global();
8310 env2->DetachGlobal();
8312 // Check that the global has been detached. No other.p property can
8314 result = CompileRun("other.p");
8315 CHECK(result.IsEmpty());
8317 // Reuse global2 for env3.
8318 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8320 v8::Handle<v8::ObjectTemplate>(),
8322 CHECK(global2->Equals(env3->Global()));
8324 // Start by using the same security token for env3 as for env1 and env2.
8325 env3->SetSecurityToken(foo);
8327 // Create a property on the global object in env3.
8329 v8::Context::Scope scope(env3);
8330 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8333 // Check that other.p is now the property in env3 and that we have access.
8334 result = CompileRun("other.p");
8335 CHECK(result->IsInt32());
8336 CHECK_EQ(24, result->Int32Value());
8338 // Change security token for env3 to something different from env1 and env2.
8339 env3->SetSecurityToken(v8_str("bar"));
8341 // Check that we do not have access to other.p in env1. |other| is now
8342 // the global object for env3 which has a different security token,
8343 // so access should be blocked.
8344 result = CompileRun("other.p");
8345 CHECK(result.IsEmpty());
8349 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8350 info.GetReturnValue().Set(
8351 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8355 TEST(DetachedAccesses) {
8357 v8::HandleScope scope(env1->GetIsolate());
8359 // Create second environment.
8360 Local<ObjectTemplate> inner_global_template =
8361 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8362 inner_global_template ->SetAccessorProperty(
8363 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8364 v8::Local<Context> env2 =
8365 Context::New(env1->GetIsolate(), NULL, inner_global_template);
8367 Local<Value> foo = v8_str("foo");
8369 // Set same security token for env1 and env2.
8370 env1->SetSecurityToken(foo);
8371 env2->SetSecurityToken(foo);
8373 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8376 v8::Context::Scope scope(env2);
8377 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8379 "function bound_x() { return x; }"
8380 "function get_x() { return this.x; }"
8381 "function get_x_w() { return (function() {return this.x;})(); }");
8382 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8383 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8384 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8385 env1->Global()->Set(
8387 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8390 Local<Object> env2_global = env2->Global();
8391 env2_global->TurnOnAccessCheck();
8392 env2->DetachGlobal();
8394 Local<Value> result;
8395 result = CompileRun("bound_x()");
8396 CHECK(v8_str("env2_x")->Equals(result));
8397 result = CompileRun("get_x()");
8398 CHECK(result.IsEmpty());
8399 result = CompileRun("get_x_w()");
8400 CHECK(result.IsEmpty());
8401 result = CompileRun("this_x()");
8402 CHECK(v8_str("env2_x")->Equals(result));
8404 // Reattach env2's proxy
8405 env2 = Context::New(env1->GetIsolate(),
8407 v8::Handle<v8::ObjectTemplate>(),
8409 env2->SetSecurityToken(foo);
8411 v8::Context::Scope scope(env2);
8412 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8413 env2->Global()->Set(v8_str("env1"), env1->Global());
8414 result = CompileRun(
8416 "for (var i = 0; i < 4; i++ ) {"
8417 " results.push(env1.bound_x());"
8418 " results.push(env1.get_x());"
8419 " results.push(env1.get_x_w());"
8420 " results.push(env1.this_x());"
8423 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8424 CHECK_EQ(16u, results->Length());
8425 for (int i = 0; i < 16; i += 4) {
8426 CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8427 CHECK(v8_str("env1_x")->Equals(results->Get(i + 1)));
8428 CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8429 CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8433 result = CompileRun(
8435 "for (var i = 0; i < 4; i++ ) {"
8436 " results.push(bound_x());"
8437 " results.push(get_x());"
8438 " results.push(get_x_w());"
8439 " results.push(this_x());"
8442 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8443 CHECK_EQ(16u, results->Length());
8444 for (int i = 0; i < 16; i += 4) {
8445 CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8446 CHECK(v8_str("env3_x")->Equals(results->Get(i + 1)));
8447 CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8448 CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8451 result = CompileRun(
8453 "for (var i = 0; i < 4; i++ ) {"
8454 " results.push(this.bound_x());"
8455 " results.push(this.get_x());"
8456 " results.push(this.get_x_w());"
8457 " results.push(this.this_x());"
8460 results = Local<v8::Array>::Cast(result);
8461 CHECK_EQ(16u, results->Length());
8462 for (int i = 0; i < 16; i += 4) {
8463 CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8464 CHECK(v8_str("env1_x")->Equals(results->Get(i + 1)));
8465 CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8466 CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8471 static bool allowed_access = false;
8472 static bool AccessBlocker(Local<v8::Object> global, Local<Value> name,
8473 v8::AccessType type, Local<Value> data) {
8474 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8479 static int g_echo_value = -1;
8482 static void EchoGetter(
8484 const v8::PropertyCallbackInfo<v8::Value>& info) {
8485 info.GetReturnValue().Set(v8_num(g_echo_value));
8489 static void EchoSetter(Local<String> name,
8491 const v8::PropertyCallbackInfo<void>&) {
8492 if (value->IsNumber())
8493 g_echo_value = value->Int32Value();
8497 static void UnreachableGetter(
8499 const v8::PropertyCallbackInfo<v8::Value>& info) {
8500 CHECK(false); // This function should not be called..
8504 static void UnreachableSetter(Local<String>,
8506 const v8::PropertyCallbackInfo<void>&) {
8507 CHECK(false); // This function should nto be called.
8511 static void UnreachableFunction(
8512 const v8::FunctionCallbackInfo<v8::Value>& info) {
8513 CHECK(false); // This function should not be called..
8517 TEST(AccessControl) {
8518 v8::Isolate* isolate = CcTest::isolate();
8519 v8::HandleScope handle_scope(isolate);
8520 v8::Handle<v8::ObjectTemplate> global_template =
8521 v8::ObjectTemplate::New(isolate);
8523 global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
8525 // Add an accessor accessible by cross-domain JS code.
8526 global_template->SetAccessor(
8527 v8_str("accessible_prop"),
8528 EchoGetter, EchoSetter,
8529 v8::Handle<Value>(),
8530 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8533 // Add an accessor that is not accessible by cross-domain JS code.
8534 global_template->SetAccessor(v8_str("blocked_prop"),
8535 UnreachableGetter, UnreachableSetter,
8536 v8::Handle<Value>(),
8539 global_template->SetAccessorProperty(
8540 v8_str("blocked_js_prop"),
8541 v8::FunctionTemplate::New(isolate, UnreachableFunction),
8542 v8::FunctionTemplate::New(isolate, UnreachableFunction),
8546 // Create an environment
8547 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8550 v8::Handle<v8::Object> global0 = context0->Global();
8552 // Define a property with JS getter and setter.
8554 "function getter() { return 'getter'; };\n"
8555 "function setter() { return 'setter'; }\n"
8556 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8558 Local<Value> getter = global0->Get(v8_str("getter"));
8559 Local<Value> setter = global0->Get(v8_str("setter"));
8561 // And define normal element.
8562 global0->Set(239, v8_str("239"));
8564 // Define an element with JS getter and setter.
8566 "function el_getter() { return 'el_getter'; };\n"
8567 "function el_setter() { return 'el_setter'; };\n"
8568 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8570 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8571 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8573 v8::HandleScope scope1(isolate);
8575 v8::Local<Context> context1 = Context::New(isolate);
8578 v8::Handle<v8::Object> global1 = context1->Global();
8579 global1->Set(v8_str("other"), global0);
8581 // Access blocked property.
8582 CompileRun("other.blocked_prop = 1");
8584 CHECK(CompileRun("other.blocked_prop").IsEmpty());
8585 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
8588 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
8590 // Access blocked element.
8591 CHECK(CompileRun("other[239] = 1").IsEmpty());
8593 CHECK(CompileRun("other[239]").IsEmpty());
8594 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
8595 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
8597 allowed_access = true;
8598 // Now we can enumerate the property.
8599 ExpectTrue("propertyIsEnumerable.call(other, '239')");
8600 allowed_access = false;
8602 // Access a property with JS accessor.
8603 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
8605 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
8606 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
8609 allowed_access = true;
8611 ExpectString("other.js_accessor_p", "getter");
8613 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8615 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8617 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8619 allowed_access = false;
8621 // Access an element with JS accessor.
8622 CHECK(CompileRun("other[42] = 2").IsEmpty());
8624 CHECK(CompileRun("other[42]").IsEmpty());
8625 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
8627 allowed_access = true;
8629 ExpectString("other[42]", "el_getter");
8630 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8631 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8632 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8634 allowed_access = false;
8636 v8::Handle<Value> value;
8638 // Access accessible property
8639 value = CompileRun("other.accessible_prop = 3");
8640 CHECK(value->IsNumber());
8641 CHECK_EQ(3, value->Int32Value());
8642 CHECK_EQ(3, g_echo_value);
8644 value = CompileRun("other.accessible_prop");
8645 CHECK(value->IsNumber());
8646 CHECK_EQ(3, value->Int32Value());
8649 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
8650 CHECK(value->IsNumber());
8651 CHECK_EQ(3, value->Int32Value());
8653 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
8654 CHECK(value->IsTrue());
8656 // Enumeration doesn't enumerate accessors from inaccessible objects in
8657 // the prototype chain even if the accessors are in themselves accessible.
8660 " var obj = { '__proto__': other };"
8662 " for (var p in obj) {"
8663 " if (p == 'accessible_prop' ||"
8664 " p == 'blocked_js_prop' ||"
8665 " p == 'blocked_js_prop') {"
8674 CHECK(value->IsTrue());
8681 TEST(AccessControlES5) {
8682 v8::Isolate* isolate = CcTest::isolate();
8683 v8::HandleScope handle_scope(isolate);
8684 v8::Handle<v8::ObjectTemplate> global_template =
8685 v8::ObjectTemplate::New(isolate);
8687 global_template->SetAccessCheckCallbacks(AccessBlocker, NULL);
8689 // Add accessible accessor.
8690 global_template->SetAccessor(
8691 v8_str("accessible_prop"),
8692 EchoGetter, EchoSetter,
8693 v8::Handle<Value>(),
8694 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8697 // Add an accessor that is not accessible by cross-domain JS code.
8698 global_template->SetAccessor(v8_str("blocked_prop"),
8699 UnreachableGetter, UnreachableSetter,
8700 v8::Handle<Value>(),
8703 // Create an environment
8704 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8707 v8::Handle<v8::Object> global0 = context0->Global();
8709 v8::Local<Context> context1 = Context::New(isolate);
8711 v8::Handle<v8::Object> global1 = context1->Global();
8712 global1->Set(v8_str("other"), global0);
8714 // Regression test for issue 1154.
8715 CHECK(CompileRun("Object.keys(other)").IsEmpty());
8716 CHECK(CompileRun("other.blocked_prop").IsEmpty());
8718 // Regression test for issue 1027.
8719 CompileRun("Object.defineProperty(\n"
8720 " other, 'blocked_prop', {configurable: false})");
8721 CHECK(CompileRun("other.blocked_prop").IsEmpty());
8722 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
8725 // Regression test for issue 1171.
8726 ExpectTrue("Object.isExtensible(other)");
8727 CompileRun("Object.preventExtensions(other)");
8728 ExpectTrue("Object.isExtensible(other)");
8730 // Object.seal and Object.freeze.
8731 CompileRun("Object.freeze(other)");
8732 ExpectTrue("Object.isExtensible(other)");
8734 CompileRun("Object.seal(other)");
8735 ExpectTrue("Object.isExtensible(other)");
8737 // Regression test for issue 1250.
8738 // Make sure that we can set the accessible accessors value using normal
8740 CompileRun("other.accessible_prop = 42");
8741 CHECK_EQ(42, g_echo_value);
8743 v8::Handle<Value> value;
8744 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
8745 value = CompileRun("other.accessible_prop == 42");
8746 CHECK(value->IsTrue());
8750 static bool AccessAlwaysBlocked(Local<v8::Object> global, Local<Value> name,
8751 v8::AccessType type, Local<Value> data) {
8752 i::PrintF("Access blocked.\n");
8757 THREADED_TEST(AccessControlGetOwnPropertyNames) {
8758 v8::Isolate* isolate = CcTest::isolate();
8759 v8::HandleScope handle_scope(isolate);
8760 v8::Handle<v8::ObjectTemplate> obj_template =
8761 v8::ObjectTemplate::New(isolate);
8763 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
8764 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8766 // Create an environment
8767 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
8770 v8::Handle<v8::Object> global0 = context0->Global();
8772 v8::HandleScope scope1(CcTest::isolate());
8774 v8::Local<Context> context1 = Context::New(isolate);
8777 v8::Handle<v8::Object> global1 = context1->Global();
8778 global1->Set(v8_str("other"), global0);
8779 global1->Set(v8_str("object"), obj_template->NewInstance());
8781 v8::Handle<Value> value;
8783 // Attempt to get the property names of the other global object and
8784 // of an object that requires access checks. Accessing the other
8785 // global object should be blocked by access checks on the global
8786 // proxy object. Accessing the object that requires access checks
8787 // is blocked by the access checks on the object itself.
8788 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
8789 CHECK(value.IsEmpty());
8791 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
8792 CHECK(value.IsEmpty());
8799 TEST(SuperAccessControl) {
8800 i::FLAG_allow_natives_syntax = true;
8801 i::FLAG_harmony_classes = true;
8802 i::FLAG_harmony_object_literals = true;
8803 v8::Isolate* isolate = CcTest::isolate();
8804 v8::HandleScope handle_scope(isolate);
8805 v8::Handle<v8::ObjectTemplate> obj_template =
8806 v8::ObjectTemplate::New(isolate);
8807 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8809 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
8812 v8::TryCatch try_catch;
8814 "var f = { m() { return super.hasOwnProperty; } }.m;"
8815 "var m = %ToMethod(f, prohibited);"
8817 CHECK(try_catch.HasCaught());
8821 v8::TryCatch try_catch;
8823 "var f = {m() { return super[42]; } }.m;"
8824 "var m = %ToMethod(f, prohibited);"
8826 CHECK(try_catch.HasCaught());
8830 v8::TryCatch try_catch;
8832 "var f = {m() { super.hasOwnProperty = function () {}; } }.m;"
8833 "var m = %ToMethod(f, prohibited);"
8835 CHECK(try_catch.HasCaught());
8839 v8::TryCatch try_catch;
8841 "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
8845 " super.x = function () {};"
8848 "var m = %ToMethod(f, prohibited);"
8850 CHECK(try_catch.HasCaught());
8855 TEST(Regress470113) {
8856 i::FLAG_harmony_classes = true;
8857 i::FLAG_harmony_object_literals = true;
8858 v8::Isolate* isolate = CcTest::isolate();
8859 v8::HandleScope handle_scope(isolate);
8860 v8::Handle<v8::ObjectTemplate> obj_template =
8861 v8::ObjectTemplate::New(isolate);
8862 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
8864 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
8867 v8::TryCatch try_catch;
8870 "class C extends Object {\n"
8871 " m() { super.powned = 'Powned!'; }\n"
8873 "let c = new C();\n"
8874 "c.m.call(prohibited)");
8876 CHECK(try_catch.HasCaught());
8881 static void ConstTenGetter(Local<String> name,
8882 const v8::PropertyCallbackInfo<v8::Value>& info) {
8883 info.GetReturnValue().Set(v8_num(10));
8887 THREADED_TEST(CrossDomainAccessors) {
8888 v8::Isolate* isolate = CcTest::isolate();
8889 v8::HandleScope handle_scope(isolate);
8891 v8::Handle<v8::FunctionTemplate> func_template =
8892 v8::FunctionTemplate::New(isolate);
8894 v8::Handle<v8::ObjectTemplate> global_template =
8895 func_template->InstanceTemplate();
8897 v8::Handle<v8::ObjectTemplate> proto_template =
8898 func_template->PrototypeTemplate();
8900 // Add an accessor to proto that's accessible by cross-domain JS code.
8901 proto_template->SetAccessor(v8_str("accessible"),
8903 v8::Handle<Value>(),
8906 // Add an accessor that is not accessible by cross-domain JS code.
8907 global_template->SetAccessor(v8_str("unreachable"),
8908 UnreachableGetter, 0,
8909 v8::Handle<Value>(),
8912 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8915 Local<v8::Object> global = context0->Global();
8916 // Add a normal property that shadows 'accessible'
8917 global->Set(v8_str("accessible"), v8_num(11));
8919 // Enter a new context.
8920 v8::HandleScope scope1(CcTest::isolate());
8921 v8::Local<Context> context1 = Context::New(isolate);
8924 v8::Handle<v8::Object> global1 = context1->Global();
8925 global1->Set(v8_str("other"), global);
8927 // Should return 10, instead of 11
8928 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
8929 CHECK(value->IsNumber());
8930 CHECK_EQ(10, value->Int32Value());
8932 value = v8_compile("other.unreachable")->Run();
8933 CHECK(value.IsEmpty());
8940 static int access_count = 0;
8942 static bool AccessCounter(Local<v8::Object> global, Local<Value> name,
8943 v8::AccessType type, Local<Value> data) {
8949 // This one is too easily disturbed by other tests.
8950 TEST(AccessControlIC) {
8953 v8::Isolate* isolate = CcTest::isolate();
8954 v8::HandleScope handle_scope(isolate);
8956 // Create an environment.
8957 v8::Local<Context> context0 = Context::New(isolate);
8960 // Create an object that requires access-check functions to be
8961 // called for cross-domain access.
8962 v8::Handle<v8::ObjectTemplate> object_template =
8963 v8::ObjectTemplate::New(isolate);
8964 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
8965 Local<v8::Object> object = object_template->NewInstance();
8967 v8::HandleScope scope1(isolate);
8969 // Create another environment.
8970 v8::Local<Context> context1 = Context::New(isolate);
8973 // Make easy access to the object from the other environment.
8974 v8::Handle<v8::Object> global1 = context1->Global();
8975 global1->Set(v8_str("obj"), object);
8977 v8::Handle<Value> value;
8979 // Check that the named access-control function is called every time.
8980 CompileRun("function testProp(obj) {"
8981 " for (var i = 0; i < 10; i++) obj.prop = 1;"
8982 " for (var j = 0; j < 10; j++) obj.prop;"
8985 value = CompileRun("testProp(obj)");
8986 CHECK(value->IsNumber());
8987 CHECK_EQ(1, value->Int32Value());
8988 CHECK_EQ(21, access_count);
8990 // Check that the named access-control function is called every time.
8991 CompileRun("var p = 'prop';"
8992 "function testKeyed(obj) {"
8993 " for (var i = 0; i < 10; i++) obj[p] = 1;"
8994 " for (var j = 0; j < 10; j++) obj[p];"
8997 // Use obj which requires access checks. No inline caching is used
8999 value = CompileRun("testKeyed(obj)");
9000 CHECK(value->IsNumber());
9001 CHECK_EQ(1, value->Int32Value());
9002 CHECK_EQ(42, access_count);
9003 // Force the inline caches into generic state and try again.
9004 CompileRun("testKeyed({ a: 0 })");
9005 CompileRun("testKeyed({ b: 0 })");
9006 value = CompileRun("testKeyed(obj)");
9007 CHECK(value->IsNumber());
9008 CHECK_EQ(1, value->Int32Value());
9009 CHECK_EQ(63, access_count);
9011 // Check that the indexed access-control function is called every time.
9014 CompileRun("function testIndexed(obj) {"
9015 " for (var i = 0; i < 10; i++) obj[0] = 1;"
9016 " for (var j = 0; j < 10; j++) obj[0];"
9019 value = CompileRun("testIndexed(obj)");
9020 CHECK(value->IsNumber());
9021 CHECK_EQ(1, value->Int32Value());
9022 CHECK_EQ(21, access_count);
9023 // Force the inline caches into generic state.
9024 CompileRun("testIndexed(new Array(1))");
9025 // Test that the indexed access check is called.
9026 value = CompileRun("testIndexed(obj)");
9027 CHECK(value->IsNumber());
9028 CHECK_EQ(1, value->Int32Value());
9029 CHECK_EQ(42, access_count);
9032 // Check that the named access check is called when invoking
9033 // functions on an object that requires access checks.
9034 CompileRun("obj.f = function() {}");
9035 CompileRun("function testCallNormal(obj) {"
9036 " for (var i = 0; i < 10; i++) obj.f();"
9038 CompileRun("testCallNormal(obj)");
9039 printf("%i\n", access_count);
9040 CHECK_EQ(11, access_count);
9042 // Force obj into slow case.
9043 value = CompileRun("delete obj.prop");
9044 CHECK(value->BooleanValue());
9045 // Force inline caches into dictionary probing mode.
9046 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
9047 // Test that the named access check is called.
9048 value = CompileRun("testProp(obj);");
9049 CHECK(value->IsNumber());
9050 CHECK_EQ(1, value->Int32Value());
9051 CHECK_EQ(33, access_count);
9053 // Force the call inline cache into dictionary probing mode.
9054 CompileRun("o.f = function() {}; testCallNormal(o)");
9055 // Test that the named access check is still called for each
9056 // invocation of the function.
9057 value = CompileRun("testCallNormal(obj)");
9058 CHECK_EQ(43, access_count);
9065 THREADED_TEST(Version) { v8::V8::GetVersion(); }
9068 static void InstanceFunctionCallback(
9069 const v8::FunctionCallbackInfo<v8::Value>& args) {
9070 ApiTestFuzzer::Fuzz();
9071 args.GetReturnValue().Set(v8_num(12));
9075 THREADED_TEST(InstanceProperties) {
9076 LocalContext context;
9077 v8::Isolate* isolate = context->GetIsolate();
9078 v8::HandleScope handle_scope(isolate);
9080 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9081 Local<ObjectTemplate> instance = t->InstanceTemplate();
9083 instance->Set(v8_str("x"), v8_num(42));
9084 instance->Set(v8_str("f"),
9085 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
9087 Local<Value> o = t->GetFunction()->NewInstance();
9089 context->Global()->Set(v8_str("i"), o);
9090 Local<Value> value = CompileRun("i.x");
9091 CHECK_EQ(42, value->Int32Value());
9093 value = CompileRun("i.f()");
9094 CHECK_EQ(12, value->Int32Value());
9098 static void GlobalObjectInstancePropertiesGet(
9099 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
9100 ApiTestFuzzer::Fuzz();
9104 THREADED_TEST(GlobalObjectInstanceProperties) {
9105 v8::Isolate* isolate = CcTest::isolate();
9106 v8::HandleScope handle_scope(isolate);
9108 Local<Value> global_object;
9110 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9111 t->InstanceTemplate()->SetHandler(
9112 v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
9113 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9114 instance_template->Set(v8_str("x"), v8_num(42));
9115 instance_template->Set(v8_str("f"),
9116 v8::FunctionTemplate::New(isolate,
9117 InstanceFunctionCallback));
9119 // The script to check how Crankshaft compiles missing global function
9120 // invocations. function g is not defined and should throw on call.
9121 const char* script =
9122 "function wrapper(call) {"
9123 " var x = 0, y = 1;"
9124 " for (var i = 0; i < 1000; i++) {"
9130 "for (var i = 0; i < 17; i++) wrapper(false);"
9132 "try { wrapper(true); } catch (e) { thrown = 1; };"
9136 LocalContext env(NULL, instance_template);
9137 // Hold on to the global object so it can be used again in another
9138 // environment initialization.
9139 global_object = env->Global();
9141 Local<Value> value = CompileRun("x");
9142 CHECK_EQ(42, value->Int32Value());
9143 value = CompileRun("f()");
9144 CHECK_EQ(12, value->Int32Value());
9145 value = CompileRun(script);
9146 CHECK_EQ(1, value->Int32Value());
9150 // Create new environment reusing the global object.
9151 LocalContext env(NULL, instance_template, global_object);
9152 Local<Value> value = CompileRun("x");
9153 CHECK_EQ(42, value->Int32Value());
9154 value = CompileRun("f()");
9155 CHECK_EQ(12, value->Int32Value());
9156 value = CompileRun(script);
9157 CHECK_EQ(1, value->Int32Value());
9162 THREADED_TEST(CallKnownGlobalReceiver) {
9163 v8::Isolate* isolate = CcTest::isolate();
9164 v8::HandleScope handle_scope(isolate);
9166 Local<Value> global_object;
9168 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9169 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9171 // The script to check that we leave global object not
9172 // global object proxy on stack when we deoptimize from inside
9173 // arguments evaluation.
9174 // To provoke error we need to both force deoptimization
9175 // from arguments evaluation and to force CallIC to take
9176 // CallIC_Miss code path that can't cope with global proxy.
9177 const char* script =
9178 "function bar(x, y) { try { } finally { } }"
9179 "function baz(x) { try { } finally { } }"
9180 "function bom(x) { try { } finally { } }"
9181 "function foo(x) { bar([x], bom(2)); }"
9182 "for (var i = 0; i < 10000; i++) foo(1);"
9187 LocalContext env(NULL, instance_template);
9188 // Hold on to the global object so it can be used again in another
9189 // environment initialization.
9190 global_object = env->Global();
9191 foo = CompileRun(script);
9195 // Create new environment reusing the global object.
9196 LocalContext env(NULL, instance_template, global_object);
9197 env->Global()->Set(v8_str("foo"), foo);
9198 CompileRun("foo()");
9203 static void ShadowFunctionCallback(
9204 const v8::FunctionCallbackInfo<v8::Value>& args) {
9205 ApiTestFuzzer::Fuzz();
9206 args.GetReturnValue().Set(v8_num(42));
9210 static int shadow_y;
9211 static int shadow_y_setter_call_count;
9212 static int shadow_y_getter_call_count;
9215 static void ShadowYSetter(Local<String>,
9217 const v8::PropertyCallbackInfo<void>&) {
9218 shadow_y_setter_call_count++;
9223 static void ShadowYGetter(Local<String> name,
9224 const v8::PropertyCallbackInfo<v8::Value>& info) {
9225 ApiTestFuzzer::Fuzz();
9226 shadow_y_getter_call_count++;
9227 info.GetReturnValue().Set(v8_num(shadow_y));
9231 static void ShadowIndexedGet(uint32_t index,
9232 const v8::PropertyCallbackInfo<v8::Value>&) {
9236 static void ShadowNamedGet(Local<Name> key,
9237 const v8::PropertyCallbackInfo<v8::Value>&) {}
9240 THREADED_TEST(ShadowObject) {
9241 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9242 v8::Isolate* isolate = CcTest::isolate();
9243 v8::HandleScope handle_scope(isolate);
9245 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
9246 LocalContext context(NULL, global_template);
9248 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9249 t->InstanceTemplate()->SetHandler(
9250 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
9251 t->InstanceTemplate()->SetHandler(
9252 v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
9253 Local<ObjectTemplate> proto = t->PrototypeTemplate();
9254 Local<ObjectTemplate> instance = t->InstanceTemplate();
9256 proto->Set(v8_str("f"),
9257 v8::FunctionTemplate::New(isolate,
9258 ShadowFunctionCallback,
9260 proto->Set(v8_str("x"), v8_num(12));
9262 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9264 Local<Value> o = t->GetFunction()->NewInstance();
9265 context->Global()->Set(v8_str("__proto__"), o);
9267 Local<Value> value =
9268 CompileRun("this.propertyIsEnumerable(0)");
9269 CHECK(value->IsBoolean());
9270 CHECK(!value->BooleanValue());
9272 value = CompileRun("x");
9273 CHECK_EQ(12, value->Int32Value());
9275 value = CompileRun("f()");
9276 CHECK_EQ(42, value->Int32Value());
9278 CompileRun("y = 43");
9279 CHECK_EQ(1, shadow_y_setter_call_count);
9280 value = CompileRun("y");
9281 CHECK_EQ(1, shadow_y_getter_call_count);
9282 CHECK_EQ(42, value->Int32Value());
9286 THREADED_TEST(HiddenPrototype) {
9287 LocalContext context;
9288 v8::Isolate* isolate = context->GetIsolate();
9289 v8::HandleScope handle_scope(isolate);
9291 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9292 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9293 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9294 t1->SetHiddenPrototype(true);
9295 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9296 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9297 t2->SetHiddenPrototype(true);
9298 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9299 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9300 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9302 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9303 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9304 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9305 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9307 // Setting the prototype on an object skips hidden prototypes.
9308 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9309 o0->Set(v8_str("__proto__"), o1);
9310 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9311 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9312 o0->Set(v8_str("__proto__"), o2);
9313 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9314 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9315 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9316 o0->Set(v8_str("__proto__"), o3);
9317 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9318 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9319 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9320 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9322 // Getting the prototype of o0 should get the first visible one
9323 // which is o3. Therefore, z should not be defined on the prototype
9325 Local<Value> proto = o0->Get(v8_str("__proto__"));
9326 CHECK(proto->IsObject());
9327 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
9331 THREADED_TEST(HiddenPrototypeSet) {
9332 LocalContext context;
9333 v8::Isolate* isolate = context->GetIsolate();
9334 v8::HandleScope handle_scope(isolate);
9336 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
9337 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
9338 ht->SetHiddenPrototype(true);
9339 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
9340 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9342 Local<v8::Object> o = ot->GetFunction()->NewInstance();
9343 Local<v8::Object> h = ht->GetFunction()->NewInstance();
9344 Local<v8::Object> p = pt->GetFunction()->NewInstance();
9345 o->Set(v8_str("__proto__"), h);
9346 h->Set(v8_str("__proto__"), p);
9348 // Setting a property that exists on the hidden prototype goes there.
9349 o->Set(v8_str("x"), v8_num(7));
9350 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
9351 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
9352 CHECK(p->Get(v8_str("x"))->IsUndefined());
9354 // Setting a new property should not be forwarded to the hidden prototype.
9355 o->Set(v8_str("y"), v8_num(6));
9356 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
9357 CHECK(h->Get(v8_str("y"))->IsUndefined());
9358 CHECK(p->Get(v8_str("y"))->IsUndefined());
9360 // Setting a property that only exists on a prototype of the hidden prototype
9361 // is treated normally again.
9362 p->Set(v8_str("z"), v8_num(8));
9363 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
9364 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9365 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9366 o->Set(v8_str("z"), v8_num(9));
9367 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
9368 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9369 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9373 // Regression test for issue 2457.
9374 THREADED_TEST(HiddenPrototypeIdentityHash) {
9375 LocalContext context;
9376 v8::HandleScope handle_scope(context->GetIsolate());
9378 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
9379 t->SetHiddenPrototype(true);
9380 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
9381 Handle<Object> p = t->GetFunction()->NewInstance();
9382 Handle<Object> o = Object::New(context->GetIsolate());
9385 int hash = o->GetIdentityHash();
9387 o->Set(v8_str("foo"), v8_num(42));
9388 DCHECK_EQ(hash, o->GetIdentityHash());
9392 THREADED_TEST(SetPrototype) {
9393 LocalContext context;
9394 v8::Isolate* isolate = context->GetIsolate();
9395 v8::HandleScope handle_scope(isolate);
9397 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9398 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9399 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9400 t1->SetHiddenPrototype(true);
9401 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9402 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9403 t2->SetHiddenPrototype(true);
9404 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9405 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9406 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9408 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9409 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9410 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9411 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9413 // Setting the prototype on an object does not skip hidden prototypes.
9414 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9415 CHECK(o0->SetPrototype(o1));
9416 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9417 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9418 CHECK(o1->SetPrototype(o2));
9419 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9420 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9421 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9422 CHECK(o2->SetPrototype(o3));
9423 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9424 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9425 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9426 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9428 // Getting the prototype of o0 should get the first visible one
9429 // which is o3. Therefore, z should not be defined on the prototype
9431 Local<Value> proto = o0->Get(v8_str("__proto__"));
9432 CHECK(proto->IsObject());
9433 CHECK(proto.As<v8::Object>()->Equals(o3));
9435 // However, Object::GetPrototype ignores hidden prototype.
9436 Local<Value> proto0 = o0->GetPrototype();
9437 CHECK(proto0->IsObject());
9438 CHECK(proto0.As<v8::Object>()->Equals(o1));
9440 Local<Value> proto1 = o1->GetPrototype();
9441 CHECK(proto1->IsObject());
9442 CHECK(proto1.As<v8::Object>()->Equals(o2));
9444 Local<Value> proto2 = o2->GetPrototype();
9445 CHECK(proto2->IsObject());
9446 CHECK(proto2.As<v8::Object>()->Equals(o3));
9450 // Getting property names of an object with a prototype chain that
9451 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
9452 // crash the runtime.
9453 THREADED_TEST(Regress91517) {
9454 i::FLAG_allow_natives_syntax = true;
9455 LocalContext context;
9456 v8::Isolate* isolate = context->GetIsolate();
9457 v8::HandleScope handle_scope(isolate);
9459 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9460 t1->SetHiddenPrototype(true);
9461 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
9462 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9463 t2->SetHiddenPrototype(true);
9464 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
9465 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
9466 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
9467 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9468 t3->SetHiddenPrototype(true);
9469 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
9470 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
9471 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
9473 // Force dictionary-based properties.
9474 i::ScopedVector<char> name_buf(1024);
9475 for (int i = 1; i <= 1000; i++) {
9476 i::SNPrintF(name_buf, "sdf%d", i);
9477 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
9480 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9481 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9482 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9483 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
9485 // Create prototype chain of hidden prototypes.
9486 CHECK(o4->SetPrototype(o3));
9487 CHECK(o3->SetPrototype(o2));
9488 CHECK(o2->SetPrototype(o1));
9490 // Call the runtime version of GetOwnPropertyNames() on the natively
9491 // created object through JavaScript.
9492 context->Global()->Set(v8_str("obj"), o4);
9493 // PROPERTY_ATTRIBUTES_NONE = 0
9494 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
9496 ExpectInt32("names.length", 1006);
9497 ExpectTrue("names.indexOf(\"baz\") >= 0");
9498 ExpectTrue("names.indexOf(\"boo\") >= 0");
9499 ExpectTrue("names.indexOf(\"foo\") >= 0");
9500 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
9501 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
9502 ExpectFalse("names[1005] == undefined");
9506 // Getting property names of an object with a hidden and inherited
9507 // prototype should not duplicate the accessor properties inherited.
9508 THREADED_TEST(Regress269562) {
9509 i::FLAG_allow_natives_syntax = true;
9510 LocalContext context;
9511 v8::HandleScope handle_scope(context->GetIsolate());
9513 Local<v8::FunctionTemplate> t1 =
9514 v8::FunctionTemplate::New(context->GetIsolate());
9515 t1->SetHiddenPrototype(true);
9517 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
9518 i1->SetAccessor(v8_str("foo"),
9519 SimpleAccessorGetter, SimpleAccessorSetter);
9520 i1->SetAccessor(v8_str("bar"),
9521 SimpleAccessorGetter, SimpleAccessorSetter);
9522 i1->SetAccessor(v8_str("baz"),
9523 SimpleAccessorGetter, SimpleAccessorSetter);
9524 i1->Set(v8_str("n1"), v8_num(1));
9525 i1->Set(v8_str("n2"), v8_num(2));
9527 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9528 Local<v8::FunctionTemplate> t2 =
9529 v8::FunctionTemplate::New(context->GetIsolate());
9530 t2->SetHiddenPrototype(true);
9532 // Inherit from t1 and mark prototype as hidden.
9534 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
9536 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9537 CHECK(o2->SetPrototype(o1));
9539 v8::Local<v8::Symbol> sym =
9540 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
9541 o1->Set(sym, v8_num(3));
9543 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
9545 // Call the runtime version of GetOwnPropertyNames() on
9546 // the natively created object through JavaScript.
9547 context->Global()->Set(v8_str("obj"), o2);
9548 context->Global()->Set(v8_str("sym"), sym);
9549 // PROPERTY_ATTRIBUTES_NONE = 0
9550 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
9552 ExpectInt32("names.length", 7);
9553 ExpectTrue("names.indexOf(\"foo\") >= 0");
9554 ExpectTrue("names.indexOf(\"bar\") >= 0");
9555 ExpectTrue("names.indexOf(\"baz\") >= 0");
9556 ExpectTrue("names.indexOf(\"n1\") >= 0");
9557 ExpectTrue("names.indexOf(\"n2\") >= 0");
9558 ExpectTrue("names.indexOf(sym) >= 0");
9559 ExpectTrue("names.indexOf(\"mine\") >= 0");
9563 THREADED_TEST(FunctionReadOnlyPrototype) {
9564 LocalContext context;
9565 v8::Isolate* isolate = context->GetIsolate();
9566 v8::HandleScope handle_scope(isolate);
9568 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9569 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9570 t1->ReadOnlyPrototype();
9571 context->Global()->Set(v8_str("func1"), t1->GetFunction());
9572 // Configured value of ReadOnly flag.
9575 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
9576 " return (descriptor['writable'] == false);"
9577 "})()")->BooleanValue());
9578 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
9580 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
9582 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9583 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9584 context->Global()->Set(v8_str("func2"), t2->GetFunction());
9585 // Default value of ReadOnly flag.
9588 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
9589 " return (descriptor['writable'] == true);"
9590 "})()")->BooleanValue());
9591 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
9595 THREADED_TEST(SetPrototypeThrows) {
9596 LocalContext context;
9597 v8::Isolate* isolate = context->GetIsolate();
9598 v8::HandleScope handle_scope(isolate);
9600 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9602 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
9603 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
9605 CHECK(o0->SetPrototype(o1));
9606 // If setting the prototype leads to the cycle, SetPrototype should
9607 // return false and keep VM in sane state.
9608 v8::TryCatch try_catch;
9609 CHECK(!o1->SetPrototype(o0));
9610 CHECK(!try_catch.HasCaught());
9611 DCHECK(!CcTest::i_isolate()->has_pending_exception());
9613 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
9617 THREADED_TEST(FunctionRemovePrototype) {
9618 LocalContext context;
9619 v8::Isolate* isolate = context->GetIsolate();
9620 v8::HandleScope handle_scope(isolate);
9622 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9623 t1->RemovePrototype();
9624 Local<v8::Function> fun = t1->GetFunction();
9625 context->Global()->Set(v8_str("fun"), fun);
9626 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
9628 v8::TryCatch try_catch;
9629 CompileRun("new fun()");
9630 CHECK(try_catch.HasCaught());
9634 CHECK(try_catch.HasCaught());
9638 THREADED_TEST(GetterSetterExceptions) {
9639 LocalContext context;
9640 v8::Isolate* isolate = context->GetIsolate();
9641 v8::HandleScope handle_scope(isolate);
9643 "function Foo() { };"
9644 "function Throw() { throw 5; };"
9646 "x.__defineSetter__('set', Throw);"
9647 "x.__defineGetter__('get', Throw);");
9648 Local<v8::Object> x =
9649 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
9650 v8::TryCatch try_catch;
9651 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9652 x->Get(v8_str("get"));
9653 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9654 x->Get(v8_str("get"));
9655 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9656 x->Get(v8_str("get"));
9657 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9658 x->Get(v8_str("get"));
9662 THREADED_TEST(Constructor) {
9663 LocalContext context;
9664 v8::Isolate* isolate = context->GetIsolate();
9665 v8::HandleScope handle_scope(isolate);
9666 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
9667 templ->SetClassName(v8_str("Fun"));
9668 Local<Function> cons = templ->GetFunction();
9669 context->Global()->Set(v8_str("Fun"), cons);
9670 Local<v8::Object> inst = cons->NewInstance();
9671 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
9672 CHECK(obj->IsJSObject());
9673 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
9674 CHECK(value->BooleanValue());
9678 static void ConstructorCallback(
9679 const v8::FunctionCallbackInfo<v8::Value>& args) {
9680 ApiTestFuzzer::Fuzz();
9683 if (args.IsConstructCall()) {
9684 Local<Object> Holder = args.Holder();
9685 This = Object::New(args.GetIsolate());
9686 Local<Value> proto = Holder->GetPrototype();
9687 if (proto->IsObject()) {
9688 This->SetPrototype(proto);
9694 This->Set(v8_str("a"), args[0]);
9695 args.GetReturnValue().Set(This);
9699 static void FakeConstructorCallback(
9700 const v8::FunctionCallbackInfo<v8::Value>& args) {
9701 ApiTestFuzzer::Fuzz();
9702 args.GetReturnValue().Set(args[0]);
9706 THREADED_TEST(ConstructorForObject) {
9707 LocalContext context;
9708 v8::Isolate* isolate = context->GetIsolate();
9709 v8::HandleScope handle_scope(isolate);
9712 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9713 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
9714 Local<Object> instance = instance_template->NewInstance();
9715 context->Global()->Set(v8_str("obj"), instance);
9716 v8::TryCatch try_catch;
9718 CHECK(!try_catch.HasCaught());
9720 // Call the Object's constructor with a 32-bit signed integer.
9721 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
9722 CHECK(!try_catch.HasCaught());
9723 CHECK(value->IsInt32());
9724 CHECK_EQ(28, value->Int32Value());
9726 Local<Value> args1[] = {v8_num(28)};
9727 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
9728 CHECK(value_obj1->IsObject());
9729 Local<Object> object1 = Local<Object>::Cast(value_obj1);
9730 value = object1->Get(v8_str("a"));
9731 CHECK(value->IsInt32());
9732 CHECK(!try_catch.HasCaught());
9733 CHECK_EQ(28, value->Int32Value());
9735 // Call the Object's constructor with a String.
9737 CompileRun("(function() { var o = new obj('tipli'); return o.a; })()");
9738 CHECK(!try_catch.HasCaught());
9739 CHECK(value->IsString());
9740 String::Utf8Value string_value1(value->ToString(isolate));
9741 CHECK_EQ(0, strcmp("tipli", *string_value1));
9743 Local<Value> args2[] = {v8_str("tipli")};
9744 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
9745 CHECK(value_obj2->IsObject());
9746 Local<Object> object2 = Local<Object>::Cast(value_obj2);
9747 value = object2->Get(v8_str("a"));
9748 CHECK(!try_catch.HasCaught());
9749 CHECK(value->IsString());
9750 String::Utf8Value string_value2(value->ToString(isolate));
9751 CHECK_EQ(0, strcmp("tipli", *string_value2));
9753 // Call the Object's constructor with a Boolean.
9754 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
9755 CHECK(!try_catch.HasCaught());
9756 CHECK(value->IsBoolean());
9757 CHECK_EQ(true, value->BooleanValue());
9759 Handle<Value> args3[] = {v8::True(isolate)};
9760 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
9761 CHECK(value_obj3->IsObject());
9762 Local<Object> object3 = Local<Object>::Cast(value_obj3);
9763 value = object3->Get(v8_str("a"));
9764 CHECK(!try_catch.HasCaught());
9765 CHECK(value->IsBoolean());
9766 CHECK_EQ(true, value->BooleanValue());
9768 // Call the Object's constructor with undefined.
9769 Handle<Value> args4[] = {v8::Undefined(isolate)};
9770 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
9771 CHECK(value_obj4->IsObject());
9772 Local<Object> object4 = Local<Object>::Cast(value_obj4);
9773 value = object4->Get(v8_str("a"));
9774 CHECK(!try_catch.HasCaught());
9775 CHECK(value->IsUndefined());
9777 // Call the Object's constructor with null.
9778 Handle<Value> args5[] = {v8::Null(isolate)};
9779 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
9780 CHECK(value_obj5->IsObject());
9781 Local<Object> object5 = Local<Object>::Cast(value_obj5);
9782 value = object5->Get(v8_str("a"));
9783 CHECK(!try_catch.HasCaught());
9784 CHECK(value->IsNull());
9787 // Check exception handling when there is no constructor set for the Object.
9789 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9790 Local<Object> instance = instance_template->NewInstance();
9791 context->Global()->Set(v8_str("obj2"), instance);
9792 v8::TryCatch try_catch;
9794 CHECK(!try_catch.HasCaught());
9796 value = CompileRun("new obj2(28)");
9797 CHECK(try_catch.HasCaught());
9798 String::Utf8Value exception_value1(try_catch.Exception());
9799 CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
9802 Local<Value> args[] = {v8_num(29)};
9803 value = instance->CallAsConstructor(1, args);
9804 CHECK(try_catch.HasCaught());
9805 String::Utf8Value exception_value2(try_catch.Exception());
9807 0, strcmp("TypeError: #<Object> is not a function", *exception_value2));
9811 // Check the case when constructor throws exception.
9813 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9814 instance_template->SetCallAsFunctionHandler(ThrowValue);
9815 Local<Object> instance = instance_template->NewInstance();
9816 context->Global()->Set(v8_str("obj3"), instance);
9817 v8::TryCatch try_catch;
9819 CHECK(!try_catch.HasCaught());
9821 value = CompileRun("new obj3(22)");
9822 CHECK(try_catch.HasCaught());
9823 String::Utf8Value exception_value1(try_catch.Exception());
9824 CHECK_EQ(0, strcmp("22", *exception_value1));
9827 Local<Value> args[] = {v8_num(23)};
9828 value = instance->CallAsConstructor(1, args);
9829 CHECK(try_catch.HasCaught());
9830 String::Utf8Value exception_value2(try_catch.Exception());
9831 CHECK_EQ(0, strcmp("23", *exception_value2));
9835 // Check whether constructor returns with an object or non-object.
9837 Local<FunctionTemplate> function_template =
9838 FunctionTemplate::New(isolate, FakeConstructorCallback);
9839 Local<Function> function = function_template->GetFunction();
9840 Local<Object> instance1 = function;
9841 context->Global()->Set(v8_str("obj4"), instance1);
9842 v8::TryCatch try_catch;
9844 CHECK(!try_catch.HasCaught());
9846 CHECK(instance1->IsObject());
9847 CHECK(instance1->IsFunction());
9849 value = CompileRun("new obj4(28)");
9850 CHECK(!try_catch.HasCaught());
9851 CHECK(value->IsObject());
9853 Local<Value> args1[] = {v8_num(28)};
9854 value = instance1->CallAsConstructor(1, args1);
9855 CHECK(!try_catch.HasCaught());
9856 CHECK(value->IsObject());
9858 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9859 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
9860 Local<Object> instance2 = instance_template->NewInstance();
9861 context->Global()->Set(v8_str("obj5"), instance2);
9862 CHECK(!try_catch.HasCaught());
9864 CHECK(instance2->IsObject());
9865 CHECK(!instance2->IsFunction());
9867 value = CompileRun("new obj5(28)");
9868 CHECK(!try_catch.HasCaught());
9869 CHECK(!value->IsObject());
9871 Local<Value> args2[] = {v8_num(28)};
9872 value = instance2->CallAsConstructor(1, args2);
9873 CHECK(!try_catch.HasCaught());
9874 CHECK(!value->IsObject());
9879 THREADED_TEST(FunctionDescriptorException) {
9880 LocalContext context;
9881 v8::Isolate* isolate = context->GetIsolate();
9882 v8::HandleScope handle_scope(isolate);
9883 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
9884 templ->SetClassName(v8_str("Fun"));
9885 Local<Function> cons = templ->GetFunction();
9886 context->Global()->Set(v8_str("Fun"), cons);
9887 Local<Value> value = CompileRun(
9890 " (new Fun()).blah()"
9892 " var str = String(e);"
9893 // " if (str.indexOf('TypeError') == -1) return 1;"
9894 // " if (str.indexOf('[object Fun]') != -1) return 2;"
9895 // " if (str.indexOf('#<Fun>') == -1) return 3;"
9901 CHECK_EQ(0, value->Int32Value());
9905 THREADED_TEST(EvalAliasedDynamic) {
9906 LocalContext current;
9907 v8::HandleScope scope(current->GetIsolate());
9909 // Tests where aliased eval can only be resolved dynamically.
9910 Local<Script> script = v8_compile(
9913 " with (x) { return eval('foo'); }"
9916 "result1 = f(new Object());"
9917 "result2 = f(this);"
9918 "var x = new Object();"
9919 "x.eval = function(x) { return 1; };"
9922 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
9923 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
9924 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
9926 v8::TryCatch try_catch;
9927 script = v8_compile(
9930 " with (x) { return eval('bar'); }"
9932 "result4 = f(this)");
9934 CHECK(!try_catch.HasCaught());
9935 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
9941 THREADED_TEST(CrossEval) {
9942 v8::HandleScope scope(CcTest::isolate());
9944 LocalContext current;
9946 Local<String> token = v8_str("<security token>");
9947 other->SetSecurityToken(token);
9948 current->SetSecurityToken(token);
9950 // Set up reference from current to other.
9951 current->Global()->Set(v8_str("other"), other->Global());
9953 // Check that new variables are introduced in other context.
9954 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
9956 Local<Value> foo = other->Global()->Get(v8_str("foo"));
9957 CHECK_EQ(1234, foo->Int32Value());
9958 CHECK(!current->Global()->Has(v8_str("foo")));
9960 // Check that writing to non-existing properties introduces them in
9961 // the other context.
9962 script = v8_compile("other.eval('na = 1234')");
9964 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
9965 CHECK(!current->Global()->Has(v8_str("na")));
9967 // Check that global variables in current context are not visible in other
9969 v8::TryCatch try_catch;
9970 script = v8_compile("var bar = 42; other.eval('bar');");
9971 Local<Value> result = script->Run();
9972 CHECK(try_catch.HasCaught());
9975 // Check that local variables in current context are not visible in other
9977 script = v8_compile(
9980 " return other.eval('baz');"
9982 result = script->Run();
9983 CHECK(try_catch.HasCaught());
9986 // Check that global variables in the other environment are visible
9987 // when evaluting code.
9988 other->Global()->Set(v8_str("bis"), v8_num(1234));
9989 script = v8_compile("other.eval('bis')");
9990 CHECK_EQ(1234, script->Run()->Int32Value());
9991 CHECK(!try_catch.HasCaught());
9993 // Check that the 'this' pointer points to the global object evaluating
9995 other->Global()->Set(v8_str("t"), other->Global());
9996 script = v8_compile("other.eval('this == t')");
9997 result = script->Run();
9998 CHECK(result->IsTrue());
9999 CHECK(!try_catch.HasCaught());
10001 // Check that variables introduced in with-statement are not visible in
10003 script = v8_compile("with({x:2}){other.eval('x')}");
10004 result = script->Run();
10005 CHECK(try_catch.HasCaught());
10008 // Check that you cannot use 'eval.call' with another object than the
10009 // current global object.
10010 script = v8_compile("other.y = 1; eval.call(other, 'y')");
10011 result = script->Run();
10012 CHECK(try_catch.HasCaught());
10016 // Test that calling eval in a context which has been detached from
10017 // its global proxy works.
10018 THREADED_TEST(EvalInDetachedGlobal) {
10019 v8::Isolate* isolate = CcTest::isolate();
10020 v8::HandleScope scope(isolate);
10022 v8::Local<Context> context0 = Context::New(isolate);
10023 v8::Local<Context> context1 = Context::New(isolate);
10025 // Set up function in context0 that uses eval from context0.
10027 v8::Handle<v8::Value> fun = CompileRun(
10031 " return function(s) { return e(s); }"
10035 // Put the function into context1 and call it before and after
10036 // detaching the global. Before detaching, the call succeeds and
10037 // after detaching and exception is thrown.
10039 context1->Global()->Set(v8_str("fun"), fun);
10040 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
10041 CHECK_EQ(42, x_value->Int32Value());
10042 context0->DetachGlobal();
10043 v8::TryCatch catcher;
10044 x_value = CompileRun("fun('x')");
10045 CHECK_EQ(42, x_value->Int32Value());
10050 THREADED_TEST(CrossLazyLoad) {
10051 v8::HandleScope scope(CcTest::isolate());
10052 LocalContext other;
10053 LocalContext current;
10055 Local<String> token = v8_str("<security token>");
10056 other->SetSecurityToken(token);
10057 current->SetSecurityToken(token);
10059 // Set up reference from current to other.
10060 current->Global()->Set(v8_str("other"), other->Global());
10062 // Trigger lazy loading in other context.
10063 Local<Script> script = v8_compile("other.eval('new Date(42)')");
10064 Local<Value> value = script->Run();
10065 CHECK_EQ(42.0, value->NumberValue());
10069 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
10070 ApiTestFuzzer::Fuzz();
10071 if (args.IsConstructCall()) {
10072 if (args[0]->IsInt32()) {
10073 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
10078 args.GetReturnValue().Set(args[0]);
10082 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
10083 args.GetReturnValue().Set(args.This());
10087 // Test that a call handler can be set for objects which will allow
10088 // non-function objects created through the API to be called as
10090 THREADED_TEST(CallAsFunction) {
10091 LocalContext context;
10092 v8::Isolate* isolate = context->GetIsolate();
10093 v8::HandleScope scope(isolate);
10096 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10097 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10098 instance_template->SetCallAsFunctionHandler(call_as_function);
10099 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10100 context->Global()->Set(v8_str("obj"), instance);
10101 v8::TryCatch try_catch;
10102 Local<Value> value;
10103 CHECK(!try_catch.HasCaught());
10105 value = CompileRun("obj(42)");
10106 CHECK(!try_catch.HasCaught());
10107 CHECK_EQ(42, value->Int32Value());
10109 value = CompileRun("(function(o){return o(49)})(obj)");
10110 CHECK(!try_catch.HasCaught());
10111 CHECK_EQ(49, value->Int32Value());
10113 // test special case of call as function
10114 value = CompileRun("[obj]['0'](45)");
10115 CHECK(!try_catch.HasCaught());
10116 CHECK_EQ(45, value->Int32Value());
10118 value = CompileRun(
10119 "obj.call = Function.prototype.call;"
10120 "obj.call(null, 87)");
10121 CHECK(!try_catch.HasCaught());
10122 CHECK_EQ(87, value->Int32Value());
10124 // Regression tests for bug #1116356: Calling call through call/apply
10125 // must work for non-function receivers.
10126 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10127 value = CompileRun(apply_99);
10128 CHECK(!try_catch.HasCaught());
10129 CHECK_EQ(99, value->Int32Value());
10131 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10132 value = CompileRun(call_17);
10133 CHECK(!try_catch.HasCaught());
10134 CHECK_EQ(17, value->Int32Value());
10136 // Check that the call-as-function handler can be called through
10138 value = CompileRun("new obj(43)");
10139 CHECK(!try_catch.HasCaught());
10140 CHECK_EQ(-43, value->Int32Value());
10142 // Check that the call-as-function handler can be called through
10144 v8::Handle<Value> args[] = {v8_num(28)};
10145 value = instance->CallAsFunction(instance, 1, args);
10146 CHECK(!try_catch.HasCaught());
10147 CHECK_EQ(28, value->Int32Value());
10151 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10152 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10153 USE(instance_template);
10154 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10155 context->Global()->Set(v8_str("obj2"), instance);
10156 v8::TryCatch try_catch;
10157 Local<Value> value;
10158 CHECK(!try_catch.HasCaught());
10160 // Call an object without call-as-function handler through the JS
10161 value = CompileRun("obj2(28)");
10162 CHECK(value.IsEmpty());
10163 CHECK(try_catch.HasCaught());
10164 String::Utf8Value exception_value1(try_catch.Exception());
10165 // TODO(verwaest): Better message
10166 CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
10169 // Call an object without call-as-function handler through the API
10170 value = CompileRun("obj2(28)");
10171 v8::Handle<Value> args[] = {v8_num(28)};
10172 value = instance->CallAsFunction(instance, 1, args);
10173 CHECK(value.IsEmpty());
10174 CHECK(try_catch.HasCaught());
10175 String::Utf8Value exception_value2(try_catch.Exception());
10176 CHECK_EQ(0, strcmp("TypeError: [object Object] is not a function",
10177 *exception_value2));
10182 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10183 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10184 instance_template->SetCallAsFunctionHandler(ThrowValue);
10185 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10186 context->Global()->Set(v8_str("obj3"), instance);
10187 v8::TryCatch try_catch;
10188 Local<Value> value;
10189 CHECK(!try_catch.HasCaught());
10191 // Catch the exception which is thrown by call-as-function handler
10192 value = CompileRun("obj3(22)");
10193 CHECK(try_catch.HasCaught());
10194 String::Utf8Value exception_value1(try_catch.Exception());
10195 CHECK_EQ(0, strcmp("22", *exception_value1));
10198 v8::Handle<Value> args[] = {v8_num(23)};
10199 value = instance->CallAsFunction(instance, 1, args);
10200 CHECK(try_catch.HasCaught());
10201 String::Utf8Value exception_value2(try_catch.Exception());
10202 CHECK_EQ(0, strcmp("23", *exception_value2));
10207 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10208 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10209 instance_template->SetCallAsFunctionHandler(ReturnThis);
10210 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10212 Local<v8::Value> a1 =
10213 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10214 CHECK(a1->StrictEquals(instance));
10215 Local<v8::Value> a2 = instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10216 CHECK(a2->StrictEquals(instance));
10217 Local<v8::Value> a3 = instance->CallAsFunction(v8_num(42), 0, NULL);
10218 CHECK(a3->StrictEquals(instance));
10219 Local<v8::Value> a4 = instance->CallAsFunction(v8_str("hello"), 0, NULL);
10220 CHECK(a4->StrictEquals(instance));
10221 Local<v8::Value> a5 = instance->CallAsFunction(v8::True(isolate), 0, NULL);
10222 CHECK(a5->StrictEquals(instance));
10227 "function ReturnThisSloppy() {"
10230 "function ReturnThisStrict() {"
10234 Local<Function> ReturnThisSloppy = Local<Function>::Cast(
10235 context->Global()->Get(v8_str("ReturnThisSloppy")));
10236 Local<Function> ReturnThisStrict = Local<Function>::Cast(
10237 context->Global()->Get(v8_str("ReturnThisStrict")));
10239 Local<v8::Value> a1 =
10240 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10241 CHECK(a1->StrictEquals(context->Global()));
10242 Local<v8::Value> a2 =
10243 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10244 CHECK(a2->StrictEquals(context->Global()));
10245 Local<v8::Value> a3 = ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10246 CHECK(a3->IsNumberObject());
10247 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10248 Local<v8::Value> a4 =
10249 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10250 CHECK(a4->IsStringObject());
10251 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10252 Local<v8::Value> a5 =
10253 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10254 CHECK(a5->IsBooleanObject());
10255 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10257 Local<v8::Value> a6 =
10258 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10259 CHECK(a6->IsUndefined());
10260 Local<v8::Value> a7 =
10261 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10262 CHECK(a7->IsNull());
10263 Local<v8::Value> a8 = ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10264 CHECK(a8->StrictEquals(v8_num(42)));
10265 Local<v8::Value> a9 =
10266 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10267 CHECK(a9->StrictEquals(v8_str("hello")));
10268 Local<v8::Value> a10 =
10269 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10270 CHECK(a10->StrictEquals(v8::True(isolate)));
10275 // Check whether a non-function object is callable.
10276 THREADED_TEST(CallableObject) {
10277 LocalContext context;
10278 v8::Isolate* isolate = context->GetIsolate();
10279 v8::HandleScope scope(isolate);
10282 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10283 instance_template->SetCallAsFunctionHandler(call_as_function);
10284 Local<Object> instance = instance_template->NewInstance();
10285 v8::TryCatch try_catch;
10287 CHECK(instance->IsCallable());
10288 CHECK(!try_catch.HasCaught());
10292 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10293 Local<Object> instance = instance_template->NewInstance();
10294 v8::TryCatch try_catch;
10296 CHECK(!instance->IsCallable());
10297 CHECK(!try_catch.HasCaught());
10301 Local<FunctionTemplate> function_template =
10302 FunctionTemplate::New(isolate, call_as_function);
10303 Local<Function> function = function_template->GetFunction();
10304 Local<Object> instance = function;
10305 v8::TryCatch try_catch;
10307 CHECK(instance->IsCallable());
10308 CHECK(!try_catch.HasCaught());
10312 Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
10313 Local<Function> function = function_template->GetFunction();
10314 Local<Object> instance = function;
10315 v8::TryCatch try_catch;
10317 CHECK(instance->IsCallable());
10318 CHECK(!try_catch.HasCaught());
10323 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
10324 v8::HandleScope scope(isolate);
10325 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
10326 for (int i = 0; i < iterations; i++) {
10327 Local<v8::Number> n(v8::Integer::New(isolate, 42));
10329 return Recurse(isolate, depth - 1, iterations);
10333 THREADED_TEST(HandleIteration) {
10334 static const int kIterations = 500;
10335 static const int kNesting = 200;
10336 LocalContext context;
10337 v8::Isolate* isolate = context->GetIsolate();
10338 v8::HandleScope scope0(isolate);
10339 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10341 v8::HandleScope scope1(isolate);
10342 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10343 for (int i = 0; i < kIterations; i++) {
10344 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
10345 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
10348 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
10350 v8::HandleScope scope2(CcTest::isolate());
10351 for (int j = 0; j < kIterations; j++) {
10352 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
10353 CHECK_EQ(j + 1 + kIterations,
10354 v8::HandleScope::NumberOfHandles(isolate));
10357 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
10359 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10360 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
10364 static void InterceptorCallICFastApi(
10365 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
10366 ApiTestFuzzer::Fuzz();
10367 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
10369 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
10371 if ((*call_count) % 20 == 0) {
10372 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
10376 static void FastApiCallback_TrivialSignature(
10377 const v8::FunctionCallbackInfo<v8::Value>& args) {
10378 ApiTestFuzzer::Fuzz();
10379 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
10380 v8::Isolate* isolate = CcTest::isolate();
10381 CHECK_EQ(isolate, args.GetIsolate());
10382 CHECK(args.This()->Equals(args.Holder()));
10383 CHECK(args.Data()->Equals(v8_str("method_data")));
10384 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10387 static void FastApiCallback_SimpleSignature(
10388 const v8::FunctionCallbackInfo<v8::Value>& args) {
10389 ApiTestFuzzer::Fuzz();
10390 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
10391 v8::Isolate* isolate = CcTest::isolate();
10392 CHECK_EQ(isolate, args.GetIsolate());
10393 CHECK(args.This()->GetPrototype()->Equals(args.Holder()));
10394 CHECK(args.Data()->Equals(v8_str("method_data")));
10395 // Note, we're using HasRealNamedProperty instead of Has to avoid
10396 // invoking the interceptor again.
10397 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
10398 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10402 // Helper to maximize the odds of object moving.
10403 static void GenerateSomeGarbage() {
10406 "for (var i = 0; i < 1000; i++) {"
10407 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
10409 "garbage = undefined;");
10413 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
10414 static int count = 0;
10415 if (count++ % 3 == 0) {
10416 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
10417 // This should move the stub
10418 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
10423 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
10424 LocalContext context;
10425 v8::Isolate* isolate = context->GetIsolate();
10426 v8::HandleScope scope(isolate);
10427 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
10428 v8::ObjectTemplate::New(isolate);
10429 nativeobject_templ->Set(isolate, "callback",
10430 v8::FunctionTemplate::New(isolate,
10431 DirectApiCallback));
10432 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10433 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10434 // call the api function multiple times to ensure direct call stub creation.
10437 " for (var i = 1; i <= 30; i++) {"
10438 " nativeobject.callback();"
10445 void ThrowingDirectApiCallback(
10446 const v8::FunctionCallbackInfo<v8::Value>& args) {
10447 args.GetIsolate()->ThrowException(v8_str("g"));
10451 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
10452 LocalContext context;
10453 v8::Isolate* isolate = context->GetIsolate();
10454 v8::HandleScope scope(isolate);
10455 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
10456 v8::ObjectTemplate::New(isolate);
10457 nativeobject_templ->Set(isolate, "callback",
10458 v8::FunctionTemplate::New(isolate,
10459 ThrowingDirectApiCallback));
10460 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10461 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10462 // call the api function multiple times to ensure direct call stub creation.
10463 v8::Handle<Value> result = CompileRun(
10466 " for (var i = 1; i <= 5; i++) {"
10467 " try { nativeobject.callback(); } catch (e) { result += e; }"
10471 CHECK(v8_str("ggggg")->Equals(result));
10475 static int p_getter_count_3;
10478 static Handle<Value> DoDirectGetter() {
10479 if (++p_getter_count_3 % 3 == 0) {
10480 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
10481 GenerateSomeGarbage();
10483 return v8_str("Direct Getter Result");
10487 static void DirectGetterCallback(
10488 Local<String> name,
10489 const v8::PropertyCallbackInfo<v8::Value>& info) {
10490 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
10491 info.GetReturnValue().Set(DoDirectGetter());
10495 template<typename Accessor>
10496 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
10497 LocalContext context;
10498 v8::Isolate* isolate = context->GetIsolate();
10499 v8::HandleScope scope(isolate);
10500 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
10501 obj->SetAccessor(v8_str("p1"), accessor);
10502 context->Global()->Set(v8_str("o1"), obj->NewInstance());
10503 p_getter_count_3 = 0;
10504 v8::Handle<v8::Value> result = CompileRun(
10506 " for (var i = 0; i < 30; i++) o1.p1;"
10510 CHECK(v8_str("Direct Getter Result")->Equals(result));
10511 CHECK_EQ(31, p_getter_count_3);
10515 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
10516 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
10520 void ThrowingDirectGetterCallback(
10521 Local<String> name,
10522 const v8::PropertyCallbackInfo<v8::Value>& info) {
10523 info.GetIsolate()->ThrowException(v8_str("g"));
10527 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
10528 LocalContext context;
10529 v8::Isolate* isolate = context->GetIsolate();
10530 v8::HandleScope scope(isolate);
10531 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
10532 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
10533 context->Global()->Set(v8_str("o1"), obj->NewInstance());
10534 v8::Handle<Value> result = CompileRun(
10536 "for (var i = 0; i < 5; i++) {"
10537 " try { o1.p1; } catch (e) { result += e; }"
10540 CHECK(v8_str("ggggg")->Equals(result));
10544 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
10545 int interceptor_call_count = 0;
10546 v8::Isolate* isolate = CcTest::isolate();
10547 v8::HandleScope scope(isolate);
10548 v8::Handle<v8::FunctionTemplate> fun_templ =
10549 v8::FunctionTemplate::New(isolate);
10550 v8::Handle<v8::FunctionTemplate> method_templ =
10551 v8::FunctionTemplate::New(isolate,
10552 FastApiCallback_TrivialSignature,
10553 v8_str("method_data"),
10554 v8::Handle<v8::Signature>());
10555 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10556 proto_templ->Set(v8_str("method"), method_templ);
10557 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10558 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10559 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10560 v8::External::New(isolate, &interceptor_call_count)));
10561 LocalContext context;
10562 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10563 GenerateSomeGarbage();
10564 context->Global()->Set(v8_str("o"), fun->NewInstance());
10567 "for (var i = 0; i < 100; i++) {"
10568 " result = o.method(41);"
10570 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10571 CHECK_EQ(100, interceptor_call_count);
10575 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
10576 int interceptor_call_count = 0;
10577 v8::Isolate* isolate = CcTest::isolate();
10578 v8::HandleScope scope(isolate);
10579 v8::Handle<v8::FunctionTemplate> fun_templ =
10580 v8::FunctionTemplate::New(isolate);
10581 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10582 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10583 v8::Signature::New(isolate, fun_templ));
10584 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10585 proto_templ->Set(v8_str("method"), method_templ);
10586 fun_templ->SetHiddenPrototype(true);
10587 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10588 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10589 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10590 v8::External::New(isolate, &interceptor_call_count)));
10591 LocalContext context;
10592 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10593 GenerateSomeGarbage();
10594 context->Global()->Set(v8_str("o"), fun->NewInstance());
10597 "var receiver = {};"
10598 "receiver.__proto__ = o;"
10600 "for (var i = 0; i < 100; i++) {"
10601 " result = receiver.method(41);"
10603 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10604 CHECK_EQ(100, interceptor_call_count);
10608 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
10609 int interceptor_call_count = 0;
10610 v8::Isolate* isolate = CcTest::isolate();
10611 v8::HandleScope scope(isolate);
10612 v8::Handle<v8::FunctionTemplate> fun_templ =
10613 v8::FunctionTemplate::New(isolate);
10614 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10615 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10616 v8::Signature::New(isolate, fun_templ));
10617 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10618 proto_templ->Set(v8_str("method"), method_templ);
10619 fun_templ->SetHiddenPrototype(true);
10620 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10621 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10622 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10623 v8::External::New(isolate, &interceptor_call_count)));
10624 LocalContext context;
10625 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10626 GenerateSomeGarbage();
10627 context->Global()->Set(v8_str("o"), fun->NewInstance());
10630 "var receiver = {};"
10631 "receiver.__proto__ = o;"
10633 "var saved_result = 0;"
10634 "for (var i = 0; i < 100; i++) {"
10635 " result = receiver.method(41);"
10637 " saved_result = result;"
10638 " receiver = {method: function(x) { return x - 1 }};"
10641 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10642 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10643 CHECK_GE(interceptor_call_count, 50);
10647 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
10648 int interceptor_call_count = 0;
10649 v8::Isolate* isolate = CcTest::isolate();
10650 v8::HandleScope scope(isolate);
10651 v8::Handle<v8::FunctionTemplate> fun_templ =
10652 v8::FunctionTemplate::New(isolate);
10653 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10654 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10655 v8::Signature::New(isolate, fun_templ));
10656 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10657 proto_templ->Set(v8_str("method"), method_templ);
10658 fun_templ->SetHiddenPrototype(true);
10659 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10660 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10661 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10662 v8::External::New(isolate, &interceptor_call_count)));
10663 LocalContext context;
10664 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10665 GenerateSomeGarbage();
10666 context->Global()->Set(v8_str("o"), fun->NewInstance());
10669 "var receiver = {};"
10670 "receiver.__proto__ = o;"
10672 "var saved_result = 0;"
10673 "for (var i = 0; i < 100; i++) {"
10674 " result = receiver.method(41);"
10676 " saved_result = result;"
10677 " o.method = function(x) { return x - 1 };"
10680 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10681 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10682 CHECK_GE(interceptor_call_count, 50);
10686 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
10687 int interceptor_call_count = 0;
10688 v8::Isolate* isolate = CcTest::isolate();
10689 v8::HandleScope scope(isolate);
10690 v8::Handle<v8::FunctionTemplate> fun_templ =
10691 v8::FunctionTemplate::New(isolate);
10692 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10693 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10694 v8::Signature::New(isolate, fun_templ));
10695 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10696 proto_templ->Set(v8_str("method"), method_templ);
10697 fun_templ->SetHiddenPrototype(true);
10698 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10699 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10700 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10701 v8::External::New(isolate, &interceptor_call_count)));
10702 LocalContext context;
10703 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10704 GenerateSomeGarbage();
10705 context->Global()->Set(v8_str("o"), fun->NewInstance());
10706 v8::TryCatch try_catch;
10709 "var receiver = {};"
10710 "receiver.__proto__ = o;"
10712 "var saved_result = 0;"
10713 "for (var i = 0; i < 100; i++) {"
10714 " result = receiver.method(41);"
10716 " saved_result = result;"
10720 CHECK(try_catch.HasCaught());
10721 // TODO(verwaest): Adjust message.
10722 CHECK(v8_str("TypeError: receiver.method is not a function")
10723 ->Equals(try_catch.Exception()->ToString(isolate)));
10724 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10725 CHECK_GE(interceptor_call_count, 50);
10729 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
10730 int interceptor_call_count = 0;
10731 v8::Isolate* isolate = CcTest::isolate();
10732 v8::HandleScope scope(isolate);
10733 v8::Handle<v8::FunctionTemplate> fun_templ =
10734 v8::FunctionTemplate::New(isolate);
10735 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10736 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10737 v8::Signature::New(isolate, fun_templ));
10738 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10739 proto_templ->Set(v8_str("method"), method_templ);
10740 fun_templ->SetHiddenPrototype(true);
10741 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10742 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10743 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10744 v8::External::New(isolate, &interceptor_call_count)));
10745 LocalContext context;
10746 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10747 GenerateSomeGarbage();
10748 context->Global()->Set(v8_str("o"), fun->NewInstance());
10749 v8::TryCatch try_catch;
10752 "var receiver = {};"
10753 "receiver.__proto__ = o;"
10755 "var saved_result = 0;"
10756 "for (var i = 0; i < 100; i++) {"
10757 " result = receiver.method(41);"
10759 " saved_result = result;"
10760 " receiver = {method: receiver.method};"
10763 CHECK(try_catch.HasCaught());
10764 CHECK(v8_str("TypeError: Illegal invocation")
10765 ->Equals(try_catch.Exception()->ToString(isolate)));
10766 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10767 CHECK_GE(interceptor_call_count, 50);
10771 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
10772 v8::Isolate* isolate = CcTest::isolate();
10773 v8::HandleScope scope(isolate);
10774 v8::Handle<v8::FunctionTemplate> fun_templ =
10775 v8::FunctionTemplate::New(isolate);
10776 v8::Handle<v8::FunctionTemplate> method_templ =
10777 v8::FunctionTemplate::New(isolate,
10778 FastApiCallback_TrivialSignature,
10779 v8_str("method_data"),
10780 v8::Handle<v8::Signature>());
10781 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10782 proto_templ->Set(v8_str("method"), method_templ);
10783 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10785 LocalContext context;
10786 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10787 GenerateSomeGarbage();
10788 context->Global()->Set(v8_str("o"), fun->NewInstance());
10791 "for (var i = 0; i < 100; i++) {"
10792 " result = o.method(41);"
10795 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10799 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
10800 v8::Isolate* isolate = CcTest::isolate();
10801 v8::HandleScope scope(isolate);
10802 v8::Handle<v8::FunctionTemplate> fun_templ =
10803 v8::FunctionTemplate::New(isolate);
10804 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10805 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10806 v8::Signature::New(isolate, fun_templ));
10807 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10808 proto_templ->Set(v8_str("method"), method_templ);
10809 fun_templ->SetHiddenPrototype(true);
10810 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10811 CHECK(!templ.IsEmpty());
10812 LocalContext context;
10813 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10814 GenerateSomeGarbage();
10815 context->Global()->Set(v8_str("o"), fun->NewInstance());
10818 "var receiver = {};"
10819 "receiver.__proto__ = o;"
10821 "for (var i = 0; i < 100; i++) {"
10822 " result = receiver.method(41);"
10825 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10829 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
10830 v8::Isolate* isolate = CcTest::isolate();
10831 v8::HandleScope scope(isolate);
10832 v8::Handle<v8::FunctionTemplate> fun_templ =
10833 v8::FunctionTemplate::New(isolate);
10834 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10835 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10836 v8::Signature::New(isolate, fun_templ));
10837 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10838 proto_templ->Set(v8_str("method"), method_templ);
10839 fun_templ->SetHiddenPrototype(true);
10840 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10841 CHECK(!templ.IsEmpty());
10842 LocalContext context;
10843 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10844 GenerateSomeGarbage();
10845 context->Global()->Set(v8_str("o"), fun->NewInstance());
10848 "var receiver = {};"
10849 "receiver.__proto__ = o;"
10851 "var saved_result = 0;"
10852 "for (var i = 0; i < 100; i++) {"
10853 " result = receiver.method(41);"
10855 " saved_result = result;"
10856 " receiver = {method: function(x) { return x - 1 }};"
10859 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10860 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10864 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
10865 v8::Isolate* isolate = CcTest::isolate();
10866 v8::HandleScope scope(isolate);
10867 v8::Handle<v8::FunctionTemplate> fun_templ =
10868 v8::FunctionTemplate::New(isolate);
10869 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10870 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10871 v8::Signature::New(isolate, fun_templ));
10872 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10873 proto_templ->Set(v8_str("method"), method_templ);
10874 fun_templ->SetHiddenPrototype(true);
10875 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10876 CHECK(!templ.IsEmpty());
10877 LocalContext context;
10878 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10879 GenerateSomeGarbage();
10880 context->Global()->Set(v8_str("o"), fun->NewInstance());
10881 v8::TryCatch try_catch;
10884 "var receiver = {};"
10885 "receiver.__proto__ = o;"
10887 "var saved_result = 0;"
10888 "for (var i = 0; i < 100; i++) {"
10889 " result = receiver.method(41);"
10891 " saved_result = result;"
10895 CHECK(try_catch.HasCaught());
10896 // TODO(verwaest): Adjust message.
10897 CHECK(v8_str("TypeError: receiver.method is not a function")
10898 ->Equals(try_catch.Exception()->ToString(isolate)));
10899 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10903 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
10904 v8::Isolate* isolate = CcTest::isolate();
10905 v8::HandleScope scope(isolate);
10906 v8::Handle<v8::FunctionTemplate> fun_templ =
10907 v8::FunctionTemplate::New(isolate);
10908 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10909 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10910 v8::Signature::New(isolate, fun_templ));
10911 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10912 proto_templ->Set(v8_str("method"), method_templ);
10913 fun_templ->SetHiddenPrototype(true);
10914 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10915 CHECK(!templ.IsEmpty());
10916 LocalContext context;
10917 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10918 GenerateSomeGarbage();
10919 context->Global()->Set(v8_str("o"), fun->NewInstance());
10920 v8::TryCatch try_catch;
10923 "var receiver = {};"
10924 "receiver.__proto__ = o;"
10926 "var saved_result = 0;"
10927 "for (var i = 0; i < 100; i++) {"
10928 " result = receiver.method(41);"
10930 " saved_result = result;"
10931 " receiver = Object.create(receiver);"
10934 CHECK(try_catch.HasCaught());
10935 CHECK(v8_str("TypeError: Illegal invocation")
10936 ->Equals(try_catch.Exception()->ToString(isolate)));
10937 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10941 static void ThrowingGetter(Local<String> name,
10942 const v8::PropertyCallbackInfo<v8::Value>& info) {
10943 ApiTestFuzzer::Fuzz();
10944 info.GetIsolate()->ThrowException(Handle<Value>());
10945 info.GetReturnValue().SetUndefined();
10949 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10950 LocalContext context;
10951 HandleScope scope(context->GetIsolate());
10953 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
10954 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10955 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10957 Local<Object> instance = templ->GetFunction()->NewInstance();
10959 Local<Object> another = Object::New(context->GetIsolate());
10960 another->SetPrototype(instance);
10962 Local<Object> with_js_getter = CompileRun(
10964 "o.__defineGetter__('f', function() { throw undefined; });\n"
10965 "o\n").As<Object>();
10966 CHECK(!with_js_getter.IsEmpty());
10968 TryCatch try_catch;
10970 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10971 CHECK(try_catch.HasCaught());
10973 CHECK(result.IsEmpty());
10975 Maybe<PropertyAttribute> attr =
10976 instance->GetRealNamedPropertyAttributes(v8_str("f"));
10977 CHECK(!try_catch.HasCaught());
10978 CHECK(Just(None) == attr);
10980 result = another->GetRealNamedProperty(v8_str("f"));
10981 CHECK(try_catch.HasCaught());
10983 CHECK(result.IsEmpty());
10985 attr = another->GetRealNamedPropertyAttributes(v8_str("f"));
10986 CHECK(!try_catch.HasCaught());
10987 CHECK(Just(None) == attr);
10989 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10990 CHECK(try_catch.HasCaught());
10992 CHECK(result.IsEmpty());
10994 attr = another->GetRealNamedPropertyAttributesInPrototypeChain(v8_str("f"));
10995 CHECK(!try_catch.HasCaught());
10996 CHECK(Just(None) == attr);
10998 result = another->Get(v8_str("f"));
10999 CHECK(try_catch.HasCaught());
11001 CHECK(result.IsEmpty());
11003 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
11004 CHECK(try_catch.HasCaught());
11006 CHECK(result.IsEmpty());
11008 attr = with_js_getter->GetRealNamedPropertyAttributes(v8_str("f"));
11009 CHECK(!try_catch.HasCaught());
11010 CHECK(Just(None) == attr);
11012 result = with_js_getter->Get(v8_str("f"));
11013 CHECK(try_catch.HasCaught());
11015 CHECK(result.IsEmpty());
11019 static void ThrowingCallbackWithTryCatch(
11020 const v8::FunctionCallbackInfo<v8::Value>& args) {
11021 TryCatch try_catch;
11022 // Verboseness is important: it triggers message delivery which can call into
11024 try_catch.SetVerbose(true);
11025 CompileRun("throw 'from JS';");
11026 CHECK(try_catch.HasCaught());
11027 CHECK(!CcTest::i_isolate()->has_pending_exception());
11028 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
11032 static int call_depth;
11035 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
11036 TryCatch try_catch;
11040 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
11041 if (--call_depth) CompileRun("throw 'ThrowInJS';");
11045 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
11046 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
11050 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
11051 Handle<String> errorMessageString = message->Get();
11052 CHECK(!errorMessageString.IsEmpty());
11053 message->GetStackTrace();
11054 message->GetScriptOrigin().ResourceName();
11058 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
11059 LocalContext context;
11060 v8::Isolate* isolate = context->GetIsolate();
11061 HandleScope scope(isolate);
11063 Local<Function> func =
11064 FunctionTemplate::New(isolate,
11065 ThrowingCallbackWithTryCatch)->GetFunction();
11066 context->Global()->Set(v8_str("func"), func);
11068 MessageCallback callbacks[] =
11069 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
11070 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
11071 MessageCallback callback = callbacks[i];
11072 if (callback != NULL) {
11073 V8::AddMessageListener(callback);
11075 // Some small number to control number of times message handler should
11076 // throw an exception.
11079 "var thrown = false;\n"
11080 "try { func(); } catch(e) { thrown = true; }\n"
11082 if (callback != NULL) {
11083 V8::RemoveMessageListeners(callback);
11089 static void ParentGetter(Local<String> name,
11090 const v8::PropertyCallbackInfo<v8::Value>& info) {
11091 ApiTestFuzzer::Fuzz();
11092 info.GetReturnValue().Set(v8_num(1));
11096 static void ChildGetter(Local<String> name,
11097 const v8::PropertyCallbackInfo<v8::Value>& info) {
11098 ApiTestFuzzer::Fuzz();
11099 info.GetReturnValue().Set(v8_num(42));
11103 THREADED_TEST(Overriding) {
11104 LocalContext context;
11105 v8::Isolate* isolate = context->GetIsolate();
11106 v8::HandleScope scope(isolate);
11108 // Parent template.
11109 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
11110 Local<ObjectTemplate> parent_instance_templ =
11111 parent_templ->InstanceTemplate();
11112 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
11114 // Template that inherits from the parent template.
11115 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
11116 Local<ObjectTemplate> child_instance_templ =
11117 child_templ->InstanceTemplate();
11118 child_templ->Inherit(parent_templ);
11119 // Override 'f'. The child version of 'f' should get called for child
11121 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
11122 // Add 'g' twice. The 'g' added last should get called for instances.
11123 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
11124 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
11126 // Add 'h' as an accessor to the proto template with ReadOnly attributes
11127 // so 'h' can be shadowed on the instance object.
11128 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
11129 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
11130 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11132 // Add 'i' as an accessor to the instance template with ReadOnly attributes
11133 // but the attribute does not have effect because it is duplicated with
11135 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
11136 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11140 // Instantiate the child template.
11141 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
11143 // Check that the child function overrides the parent one.
11144 context->Global()->Set(v8_str("o"), instance);
11145 Local<Value> value = v8_compile("o.f")->Run();
11146 // Check that the 'g' that was added last is hit.
11147 CHECK_EQ(42, value->Int32Value());
11148 value = v8_compile("o.g")->Run();
11149 CHECK_EQ(42, value->Int32Value());
11151 // Check that 'h' cannot be shadowed.
11152 value = v8_compile("o.h = 3; o.h")->Run();
11153 CHECK_EQ(1, value->Int32Value());
11155 // Check that 'i' cannot be shadowed or changed.
11156 value = v8_compile("o.i = 3; o.i")->Run();
11157 CHECK_EQ(42, value->Int32Value());
11161 static void IsConstructHandler(
11162 const v8::FunctionCallbackInfo<v8::Value>& args) {
11163 ApiTestFuzzer::Fuzz();
11164 args.GetReturnValue().Set(args.IsConstructCall());
11168 THREADED_TEST(IsConstructCall) {
11169 v8::Isolate* isolate = CcTest::isolate();
11170 v8::HandleScope scope(isolate);
11172 // Function template with call handler.
11173 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11174 templ->SetCallHandler(IsConstructHandler);
11176 LocalContext context;
11178 context->Global()->Set(v8_str("f"), templ->GetFunction());
11179 Local<Value> value = v8_compile("f()")->Run();
11180 CHECK(!value->BooleanValue());
11181 value = v8_compile("new f()")->Run();
11182 CHECK(value->BooleanValue());
11186 THREADED_TEST(ObjectProtoToString) {
11187 v8::Isolate* isolate = CcTest::isolate();
11188 v8::HandleScope scope(isolate);
11189 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11190 templ->SetClassName(v8_str("MyClass"));
11192 LocalContext context;
11194 Local<String> customized_tostring = v8_str("customized toString");
11196 // Replace Object.prototype.toString
11197 v8_compile("Object.prototype.toString = function() {"
11198 " return 'customized toString';"
11201 // Normal ToString call should call replaced Object.prototype.toString
11202 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11203 Local<String> value = instance->ToString(isolate);
11204 CHECK(value->IsString() && value->Equals(customized_tostring));
11206 // ObjectProtoToString should not call replace toString function.
11207 value = instance->ObjectProtoToString();
11208 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11211 value = context->Global()->ObjectProtoToString();
11212 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11214 // Check ordinary object
11215 Local<Value> object = v8_compile("new Object()")->Run();
11216 value = object.As<v8::Object>()->ObjectProtoToString();
11217 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11221 TEST(ObjectProtoToStringES6) {
11222 // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
11223 i::FLAG_harmony_tostring = true;
11224 LocalContext context;
11225 v8::Isolate* isolate = CcTest::isolate();
11226 v8::HandleScope scope(isolate);
11227 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11228 templ->SetClassName(v8_str("MyClass"));
11230 Local<String> customized_tostring = v8_str("customized toString");
11232 // Replace Object.prototype.toString
11234 "Object.prototype.toString = function() {"
11235 " return 'customized toString';"
11238 // Normal ToString call should call replaced Object.prototype.toString
11239 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11240 Local<String> value = instance->ToString(isolate);
11241 CHECK(value->IsString() && value->Equals(customized_tostring));
11243 // ObjectProtoToString should not call replace toString function.
11244 value = instance->ObjectProtoToString();
11245 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11248 value = context->Global()->ObjectProtoToString();
11249 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11251 // Check ordinary object
11252 Local<Value> object = CompileRun("new Object()");
11253 value = object.As<v8::Object>()->ObjectProtoToString();
11254 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11256 // Check that ES6 semantics using @@toStringTag work
11257 Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
11259 #define TEST_TOSTRINGTAG(type, tag, expected) \
11261 object = CompileRun("new " #type "()"); \
11262 object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
11263 value = object.As<v8::Object>()->ObjectProtoToString(); \
11264 CHECK(value->IsString() && \
11265 value->Equals(v8_str("[object " #expected "]"))); \
11268 TEST_TOSTRINGTAG(Array, Object, Object);
11269 TEST_TOSTRINGTAG(Object, Arguments, Arguments);
11270 TEST_TOSTRINGTAG(Object, Array, Array);
11271 TEST_TOSTRINGTAG(Object, Boolean, Boolean);
11272 TEST_TOSTRINGTAG(Object, Date, Date);
11273 TEST_TOSTRINGTAG(Object, Error, Error);
11274 TEST_TOSTRINGTAG(Object, Function, Function);
11275 TEST_TOSTRINGTAG(Object, Number, Number);
11276 TEST_TOSTRINGTAG(Object, RegExp, RegExp);
11277 TEST_TOSTRINGTAG(Object, String, String);
11278 TEST_TOSTRINGTAG(Object, Foo, Foo);
11280 #undef TEST_TOSTRINGTAG
11282 Local<v8::RegExp> valueRegExp = v8::RegExp::New(v8_str("^$"),
11283 v8::RegExp::kNone);
11284 Local<Value> valueNumber = v8_num(123);
11285 Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
11286 Local<v8::Function> valueFunction =
11287 CompileRun("(function fn() {})").As<v8::Function>();
11288 Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
11289 Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
11290 Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
11292 #define TEST_TOSTRINGTAG(type, tagValue, expected) \
11294 object = CompileRun("new " #type "()"); \
11295 object.As<v8::Object>()->Set(toStringTag, tagValue); \
11296 value = object.As<v8::Object>()->ObjectProtoToString(); \
11297 CHECK(value->IsString() && \
11298 value->Equals(v8_str("[object " #expected "]"))); \
11301 #define TEST_TOSTRINGTAG_TYPES(tagValue) \
11302 TEST_TOSTRINGTAG(Array, tagValue, Array); \
11303 TEST_TOSTRINGTAG(Object, tagValue, Object); \
11304 TEST_TOSTRINGTAG(Function, tagValue, Function); \
11305 TEST_TOSTRINGTAG(Date, tagValue, Date); \
11306 TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \
11307 TEST_TOSTRINGTAG(Error, tagValue, Error); \
11309 // Test non-String-valued @@toStringTag
11310 TEST_TOSTRINGTAG_TYPES(valueRegExp);
11311 TEST_TOSTRINGTAG_TYPES(valueNumber);
11312 TEST_TOSTRINGTAG_TYPES(valueSymbol);
11313 TEST_TOSTRINGTAG_TYPES(valueFunction);
11314 TEST_TOSTRINGTAG_TYPES(valueObject);
11315 TEST_TOSTRINGTAG_TYPES(valueNull);
11316 TEST_TOSTRINGTAG_TYPES(valueUndef);
11318 #undef TEST_TOSTRINGTAG
11319 #undef TEST_TOSTRINGTAG_TYPES
11321 // @@toStringTag getter throws
11322 Local<Value> obj = v8::Object::New(isolate);
11323 obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
11325 TryCatch try_catch;
11326 value = obj.As<v8::Object>()->ObjectProtoToString();
11327 CHECK(value.IsEmpty());
11328 CHECK(try_catch.HasCaught());
11331 // @@toStringTag getter does not throw
11332 obj = v8::Object::New(isolate);
11333 obj.As<v8::Object>()->SetAccessor(
11334 toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
11336 TryCatch try_catch;
11337 value = obj.As<v8::Object>()->ObjectProtoToString();
11338 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11339 CHECK(!try_catch.HasCaught());
11342 // JS @@toStringTag value
11343 obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
11345 TryCatch try_catch;
11346 value = obj.As<v8::Object>()->ObjectProtoToString();
11347 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11348 CHECK(!try_catch.HasCaught());
11351 // JS @@toStringTag getter throws
11353 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
11354 " get: function() { throw 'Test'; }"
11357 TryCatch try_catch;
11358 value = obj.As<v8::Object>()->ObjectProtoToString();
11359 CHECK(value.IsEmpty());
11360 CHECK(try_catch.HasCaught());
11363 // JS @@toStringTag getter does not throw
11365 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
11366 " get: function() { return 'Test'; }"
11369 TryCatch try_catch;
11370 value = obj.As<v8::Object>()->ObjectProtoToString();
11371 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11372 CHECK(!try_catch.HasCaught());
11377 THREADED_TEST(ObjectGetConstructorName) {
11378 v8::Isolate* isolate = CcTest::isolate();
11379 LocalContext context;
11380 v8::HandleScope scope(isolate);
11381 v8_compile("function Parent() {};"
11382 "function Child() {};"
11383 "Child.prototype = new Parent();"
11384 "var outer = { inner: function() { } };"
11385 "var p = new Parent();"
11386 "var c = new Child();"
11387 "var x = new outer.inner();")->Run();
11389 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
11390 CHECK(p->IsObject() &&
11391 p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
11393 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
11394 CHECK(c->IsObject() &&
11395 c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
11397 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
11398 CHECK(x->IsObject() &&
11399 x->ToObject(isolate)->GetConstructorName()->Equals(
11400 v8_str("outer.inner")));
11404 bool ApiTestFuzzer::fuzzing_ = false;
11405 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
11406 int ApiTestFuzzer::active_tests_;
11407 int ApiTestFuzzer::tests_being_run_;
11408 int ApiTestFuzzer::current_;
11411 // We are in a callback and want to switch to another thread (if we
11412 // are currently running the thread fuzzing test).
11413 void ApiTestFuzzer::Fuzz() {
11414 if (!fuzzing_) return;
11415 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
11416 test->ContextSwitch();
11420 // Let the next thread go. Since it is also waiting on the V8 lock it may
11421 // not start immediately.
11422 bool ApiTestFuzzer::NextThread() {
11423 int test_position = GetNextTestNumber();
11424 const char* test_name = RegisterThreadedTest::nth(current_)->name();
11425 if (test_position == current_) {
11427 printf("Stay with %s\n", test_name);
11430 if (kLogThreading) {
11431 printf("Switch from %s to %s\n",
11433 RegisterThreadedTest::nth(test_position)->name());
11435 current_ = test_position;
11436 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
11441 void ApiTestFuzzer::Run() {
11442 // When it is our turn...
11445 // ... get the V8 lock and start running the test.
11446 v8::Locker locker(CcTest::isolate());
11449 // This test finished.
11452 // If it was the last then signal that fact.
11453 if (active_tests_ == 0) {
11454 all_tests_done_.Signal();
11456 // Otherwise select a new test and start that.
11462 static unsigned linear_congruential_generator;
11465 void ApiTestFuzzer::SetUp(PartOfTest part) {
11466 linear_congruential_generator = i::FLAG_testing_prng_seed;
11468 int count = RegisterThreadedTest::count();
11469 int start = count * part / (LAST_PART + 1);
11470 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
11471 active_tests_ = tests_being_run_ = end - start + 1;
11472 for (int i = 0; i < tests_being_run_; i++) {
11473 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
11475 for (int i = 0; i < active_tests_; i++) {
11476 RegisterThreadedTest::nth(i)->fuzzer_->Start();
11481 static void CallTestNumber(int test_number) {
11482 (RegisterThreadedTest::nth(test_number)->callback())();
11486 void ApiTestFuzzer::RunAllTests() {
11487 // Set off the first test.
11490 // Wait till they are all done.
11491 all_tests_done_.Wait();
11495 int ApiTestFuzzer::GetNextTestNumber() {
11498 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
11499 linear_congruential_generator *= 1664525u;
11500 linear_congruential_generator += 1013904223u;
11501 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
11506 void ApiTestFuzzer::ContextSwitch() {
11507 // If the new thread is the same as the current thread there is nothing to do.
11508 if (NextThread()) {
11509 // Now it can start.
11510 v8::Unlocker unlocker(CcTest::isolate());
11511 // Wait till someone starts us again.
11518 void ApiTestFuzzer::TearDown() {
11520 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
11521 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
11522 if (fuzzer != NULL) fuzzer->Join();
11527 // Lets not be needlessly self-referential.
11529 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
11530 ApiTestFuzzer::RunAllTests();
11531 ApiTestFuzzer::TearDown();
11536 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
11537 ApiTestFuzzer::RunAllTests();
11538 ApiTestFuzzer::TearDown();
11543 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
11544 ApiTestFuzzer::RunAllTests();
11545 ApiTestFuzzer::TearDown();
11550 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
11551 ApiTestFuzzer::RunAllTests();
11552 ApiTestFuzzer::TearDown();
11556 void ApiTestFuzzer::CallTest() {
11557 v8::Isolate::Scope scope(CcTest::isolate());
11559 printf("Start test %d\n", test_number_);
11560 CallTestNumber(test_number_);
11562 printf("End test %d\n", test_number_);
11566 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
11567 v8::Isolate* isolate = args.GetIsolate();
11568 CHECK(v8::Locker::IsLocked(isolate));
11569 ApiTestFuzzer::Fuzz();
11570 v8::Unlocker unlocker(isolate);
11571 const char* code = "throw 7;";
11573 v8::Locker nested_locker(isolate);
11574 v8::HandleScope scope(isolate);
11575 v8::Handle<Value> exception;
11576 { v8::TryCatch try_catch;
11577 v8::Handle<Value> value = CompileRun(code);
11578 CHECK(value.IsEmpty());
11579 CHECK(try_catch.HasCaught());
11580 // Make sure to wrap the exception in a new handle because
11581 // the handle returned from the TryCatch is destroyed
11582 // when the TryCatch is destroyed.
11583 exception = Local<Value>::New(isolate, try_catch.Exception());
11585 args.GetIsolate()->ThrowException(exception);
11590 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
11591 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
11592 ApiTestFuzzer::Fuzz();
11593 v8::Unlocker unlocker(CcTest::isolate());
11594 const char* code = "throw 7;";
11596 v8::Locker nested_locker(CcTest::isolate());
11597 v8::HandleScope scope(args.GetIsolate());
11598 v8::Handle<Value> value = CompileRun(code);
11599 CHECK(value.IsEmpty());
11600 args.GetReturnValue().Set(v8_str("foo"));
11605 // These are locking tests that don't need to be run again
11606 // as part of the locking aggregation tests.
11607 TEST(NestedLockers) {
11608 v8::Isolate* isolate = CcTest::isolate();
11609 v8::Locker locker(isolate);
11610 CHECK(v8::Locker::IsLocked(isolate));
11612 v8::HandleScope scope(env->GetIsolate());
11613 Local<v8::FunctionTemplate> fun_templ =
11614 v8::FunctionTemplate::New(isolate, ThrowInJS);
11615 Local<Function> fun = fun_templ->GetFunction();
11616 env->Global()->Set(v8_str("throw_in_js"), fun);
11617 Local<Script> script = v8_compile("(function () {"
11625 CHECK_EQ(91, script->Run()->Int32Value());
11629 // These are locking tests that don't need to be run again
11630 // as part of the locking aggregation tests.
11631 TEST(NestedLockersNoTryCatch) {
11632 v8::Locker locker(CcTest::isolate());
11634 v8::HandleScope scope(env->GetIsolate());
11635 Local<v8::FunctionTemplate> fun_templ =
11636 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
11637 Local<Function> fun = fun_templ->GetFunction();
11638 env->Global()->Set(v8_str("throw_in_js"), fun);
11639 Local<Script> script = v8_compile("(function () {"
11647 CHECK_EQ(91, script->Run()->Int32Value());
11651 THREADED_TEST(RecursiveLocking) {
11652 v8::Locker locker(CcTest::isolate());
11654 v8::Locker locker2(CcTest::isolate());
11655 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
11660 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
11661 ApiTestFuzzer::Fuzz();
11662 v8::Unlocker unlocker(CcTest::isolate());
11666 THREADED_TEST(LockUnlockLock) {
11668 v8::Locker locker(CcTest::isolate());
11669 v8::HandleScope scope(CcTest::isolate());
11671 Local<v8::FunctionTemplate> fun_templ =
11672 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
11673 Local<Function> fun = fun_templ->GetFunction();
11674 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11675 Local<Script> script = v8_compile("(function () {"
11676 " unlock_for_a_moment();"
11679 CHECK_EQ(42, script->Run()->Int32Value());
11682 v8::Locker locker(CcTest::isolate());
11683 v8::HandleScope scope(CcTest::isolate());
11685 Local<v8::FunctionTemplate> fun_templ =
11686 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
11687 Local<Function> fun = fun_templ->GetFunction();
11688 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11689 Local<Script> script = v8_compile("(function () {"
11690 " unlock_for_a_moment();"
11693 CHECK_EQ(42, script->Run()->Int32Value());
11698 static int GetGlobalObjectsCount() {
11700 i::HeapIterator it(CcTest::heap());
11701 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
11702 if (object->IsJSGlobalObject()) count++;
11707 static void CheckSurvivingGlobalObjectsCount(int expected) {
11708 // We need to collect all garbage twice to be sure that everything
11709 // has been collected. This is because inline caches are cleared in
11710 // the first garbage collection but some of the maps have already
11711 // been marked at that point. Therefore some of the maps are not
11712 // collected until the second garbage collection.
11713 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11714 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
11715 int count = GetGlobalObjectsCount();
11717 if (count != expected) CcTest::heap()->TracePathToGlobal();
11719 CHECK_EQ(expected, count);
11723 TEST(DontLeakGlobalObjects) {
11724 // Regression test for issues 1139850 and 1174891.
11726 i::FLAG_expose_gc = true;
11727 v8::V8::Initialize();
11729 for (int i = 0; i < 5; i++) {
11730 { v8::HandleScope scope(CcTest::isolate());
11731 LocalContext context;
11733 CcTest::isolate()->ContextDisposedNotification();
11734 CheckSurvivingGlobalObjectsCount(0);
11736 { v8::HandleScope scope(CcTest::isolate());
11737 LocalContext context;
11738 v8_compile("Date")->Run();
11740 CcTest::isolate()->ContextDisposedNotification();
11741 CheckSurvivingGlobalObjectsCount(0);
11743 { v8::HandleScope scope(CcTest::isolate());
11744 LocalContext context;
11745 v8_compile("/aaa/")->Run();
11747 CcTest::isolate()->ContextDisposedNotification();
11748 CheckSurvivingGlobalObjectsCount(0);
11750 { v8::HandleScope scope(CcTest::isolate());
11751 const char* extension_list[] = { "v8/gc" };
11752 v8::ExtensionConfiguration extensions(1, extension_list);
11753 LocalContext context(&extensions);
11754 v8_compile("gc();")->Run();
11756 CcTest::isolate()->ContextDisposedNotification();
11757 CheckSurvivingGlobalObjectsCount(0);
11762 TEST(CopyablePersistent) {
11763 LocalContext context;
11764 v8::Isolate* isolate = context->GetIsolate();
11765 i::GlobalHandles* globals =
11766 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
11767 int initial_handles = globals->global_handles_count();
11768 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
11771 CopyableObject handle1;
11773 v8::HandleScope scope(isolate);
11774 handle1.Reset(isolate, v8::Object::New(isolate));
11776 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
11777 CopyableObject handle2;
11779 CHECK(handle1 == handle2);
11780 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
11781 CopyableObject handle3(handle2);
11782 CHECK(handle1 == handle3);
11783 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
11785 // Verify autodispose
11786 CHECK_EQ(initial_handles, globals->global_handles_count());
11790 static void WeakApiCallback(
11791 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
11792 Local<Value> value = data.GetValue()->Get(v8_str("key"));
11793 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
11794 data.GetParameter()->Reset();
11795 delete data.GetParameter();
11799 TEST(WeakCallbackApi) {
11800 LocalContext context;
11801 v8::Isolate* isolate = context->GetIsolate();
11802 i::GlobalHandles* globals =
11803 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
11804 int initial_handles = globals->global_handles_count();
11806 v8::HandleScope scope(isolate);
11807 v8::Local<v8::Object> obj = v8::Object::New(isolate);
11808 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
11809 v8::Persistent<v8::Object>* handle =
11810 new v8::Persistent<v8::Object>(isolate, obj);
11811 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
11814 reinterpret_cast<i::Isolate*>(isolate)->heap()->
11815 CollectAllGarbage(i::Heap::kNoGCFlags);
11816 // Verify disposed.
11817 CHECK_EQ(initial_handles, globals->global_handles_count());
11821 v8::Persistent<v8::Object> some_object;
11822 v8::Persistent<v8::Object> bad_handle;
11824 void NewPersistentHandleCallback(
11825 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11826 v8::HandleScope scope(data.GetIsolate());
11827 bad_handle.Reset(data.GetIsolate(), some_object);
11828 data.GetParameter()->Reset();
11832 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
11833 LocalContext context;
11834 v8::Isolate* isolate = context->GetIsolate();
11836 v8::Persistent<v8::Object> handle1, handle2;
11838 v8::HandleScope scope(isolate);
11839 some_object.Reset(isolate, v8::Object::New(isolate));
11840 handle1.Reset(isolate, v8::Object::New(isolate));
11841 handle2.Reset(isolate, v8::Object::New(isolate));
11843 // Note: order is implementation dependent alas: currently
11844 // global handle nodes are processed by PostGarbageCollectionProcessing
11845 // in reverse allocation order, so if second allocated handle is deleted,
11846 // weak callback of the first handle would be able to 'reallocate' it.
11847 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
11849 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11853 v8::Persistent<v8::Object> to_be_disposed;
11855 void DisposeAndForceGcCallback(
11856 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11857 to_be_disposed.Reset();
11858 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11859 data.GetParameter()->Reset();
11863 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11864 LocalContext context;
11865 v8::Isolate* isolate = context->GetIsolate();
11867 v8::Persistent<v8::Object> handle1, handle2;
11869 v8::HandleScope scope(isolate);
11870 handle1.Reset(isolate, v8::Object::New(isolate));
11871 handle2.Reset(isolate, v8::Object::New(isolate));
11873 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
11874 to_be_disposed.Reset(isolate, handle2);
11875 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11878 void DisposingCallback(
11879 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11880 data.GetParameter()->Reset();
11883 void HandleCreatingCallback(
11884 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11885 v8::HandleScope scope(data.GetIsolate());
11886 v8::Persistent<v8::Object>(data.GetIsolate(),
11887 v8::Object::New(data.GetIsolate()));
11888 data.GetParameter()->Reset();
11892 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11893 LocalContext context;
11894 v8::Isolate* isolate = context->GetIsolate();
11896 v8::Persistent<v8::Object> handle1, handle2, handle3;
11898 v8::HandleScope scope(isolate);
11899 handle3.Reset(isolate, v8::Object::New(isolate));
11900 handle2.Reset(isolate, v8::Object::New(isolate));
11901 handle1.Reset(isolate, v8::Object::New(isolate));
11903 handle2.SetWeak(&handle2, DisposingCallback);
11904 handle3.SetWeak(&handle3, HandleCreatingCallback);
11905 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11909 THREADED_TEST(CheckForCrossContextObjectLiterals) {
11910 v8::V8::Initialize();
11913 const char* sources[nof] = {
11914 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11918 for (int i = 0; i < nof; i++) {
11919 const char* source = sources[i];
11920 { v8::HandleScope scope(CcTest::isolate());
11921 LocalContext context;
11922 CompileRun(source);
11924 { v8::HandleScope scope(CcTest::isolate());
11925 LocalContext context;
11926 CompileRun(source);
11932 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
11933 v8::EscapableHandleScope inner(env->GetIsolate());
11935 v8::Local<Value> three = v8_num(3);
11936 v8::Local<Value> value = inner.Escape(three);
11942 THREADED_TEST(NestedHandleScopeAndContexts) {
11943 v8::Isolate* isolate = CcTest::isolate();
11944 v8::HandleScope outer(isolate);
11945 v8::Local<Context> env = Context::New(isolate);
11947 v8::Handle<Value> value = NestedScope(env);
11948 v8::Handle<String> str(value->ToString(isolate));
11949 CHECK(!str.IsEmpty());
11954 static bool MatchPointers(void* key1, void* key2) {
11955 return key1 == key2;
11959 struct SymbolInfo {
11966 class SetFunctionEntryHookTest {
11968 SetFunctionEntryHookTest() {
11969 CHECK(instance_ == NULL);
11972 ~SetFunctionEntryHookTest() {
11973 CHECK(instance_ == this);
11978 symbol_locations_.clear();
11979 invocations_.clear();
11982 void OnJitEvent(const v8::JitCodeEvent* event);
11983 static void JitEvent(const v8::JitCodeEvent* event) {
11984 CHECK(instance_ != NULL);
11985 instance_->OnJitEvent(event);
11988 void OnEntryHook(uintptr_t function,
11989 uintptr_t return_addr_location);
11990 static void EntryHook(uintptr_t function,
11991 uintptr_t return_addr_location) {
11992 CHECK(instance_ != NULL);
11993 instance_->OnEntryHook(function, return_addr_location);
11996 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11997 CHECK(instance_ != NULL);
11998 args.GetReturnValue().Set(v8_num(42));
12000 void RunLoopInNewEnv(v8::Isolate* isolate);
12002 // Records addr as location of symbol.
12003 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
12005 // Finds the symbol containing addr
12006 SymbolInfo* FindSymbolForAddr(i::Address addr);
12007 // Returns the number of invocations where the caller name contains
12008 // \p caller_name and the function name contains \p function_name.
12009 int CountInvocations(const char* caller_name,
12010 const char* function_name);
12012 i::Handle<i::JSFunction> foo_func_;
12013 i::Handle<i::JSFunction> bar_func_;
12015 typedef std::map<size_t, SymbolInfo> SymbolMap;
12016 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
12017 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
12018 SymbolMap symbols_;
12019 SymbolLocationMap symbol_locations_;
12020 InvocationMap invocations_;
12022 static SetFunctionEntryHookTest* instance_;
12024 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
12027 // Returns true if addr is in the range [start, start+len).
12028 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
12029 if (start <= addr && start + len > addr)
12035 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
12036 SymbolInfo* symbol) {
12037 // Insert the symbol at the new location.
12038 SymbolLocationMap::iterator it =
12039 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
12040 // Now erase symbols to the left and right that overlap this one.
12041 while (it != symbol_locations_.begin()) {
12042 SymbolLocationMap::iterator left = it;
12044 if (!Overlaps(left->first, left->second->size, addr))
12046 symbol_locations_.erase(left);
12049 // Now erase symbols to the left and right that overlap this one.
12051 SymbolLocationMap::iterator right = it;
12053 if (right == symbol_locations_.end())
12055 if (!Overlaps(addr, symbol->size, right->first))
12057 symbol_locations_.erase(right);
12062 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
12063 switch (event->type) {
12064 case v8::JitCodeEvent::CODE_ADDED: {
12065 CHECK(event->code_start != NULL);
12066 CHECK_NE(0, static_cast<int>(event->code_len));
12067 CHECK(event->name.str != NULL);
12068 size_t symbol_id = symbols_.size();
12070 // Record the new symbol.
12071 SymbolInfo& info = symbols_[symbol_id];
12072 info.id = symbol_id;
12073 info.size = event->code_len;
12074 info.name.assign(event->name.str, event->name.str + event->name.len);
12076 // And record it's location.
12077 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
12081 case v8::JitCodeEvent::CODE_MOVED: {
12082 // We would like to never see code move that we haven't seen before,
12083 // but the code creation event does not happen until the line endings
12084 // have been calculated (this is so that we can report the line in the
12085 // script at which the function source is found, see
12086 // Compiler::RecordFunctionCompilation) and the line endings
12087 // calculations can cause a GC, which can move the newly created code
12088 // before its existence can be logged.
12089 SymbolLocationMap::iterator it(
12090 symbol_locations_.find(
12091 reinterpret_cast<i::Address>(event->code_start)));
12092 if (it != symbol_locations_.end()) {
12093 // Found a symbol at this location, move it.
12094 SymbolInfo* info = it->second;
12095 symbol_locations_.erase(it);
12096 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
12105 void SetFunctionEntryHookTest::OnEntryHook(
12106 uintptr_t function, uintptr_t return_addr_location) {
12107 // Get the function's code object.
12108 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
12109 reinterpret_cast<i::Address>(function));
12110 CHECK(function_code != NULL);
12112 // Then try and look up the caller's code object.
12113 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
12115 // Count the invocation.
12116 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
12117 SymbolInfo* function_symbol =
12118 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
12119 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
12121 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
12122 // Check that we have a symbol for the "bar" function at the right location.
12123 SymbolLocationMap::iterator it(
12124 symbol_locations_.find(function_code->instruction_start()));
12125 CHECK(it != symbol_locations_.end());
12128 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
12129 // Check that we have a symbol for "foo" at the right location.
12130 SymbolLocationMap::iterator it(
12131 symbol_locations_.find(function_code->instruction_start()));
12132 CHECK(it != symbol_locations_.end());
12137 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
12138 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
12139 // Do we have a direct hit on a symbol?
12140 if (it != symbol_locations_.end()) {
12141 if (it->first == addr)
12145 // If not a direct hit, it'll have to be the previous symbol.
12146 if (it == symbol_locations_.begin())
12150 size_t offs = addr - it->first;
12151 if (offs < it->second->size)
12158 int SetFunctionEntryHookTest::CountInvocations(
12159 const char* caller_name, const char* function_name) {
12160 InvocationMap::iterator it(invocations_.begin());
12161 int invocations = 0;
12162 for (; it != invocations_.end(); ++it) {
12163 SymbolInfo* caller = it->first.first;
12164 SymbolInfo* function = it->first.second;
12166 // Filter out non-matching functions.
12167 if (function_name != NULL) {
12168 if (function->name.find(function_name) == std::string::npos)
12172 // Filter out non-matching callers.
12173 if (caller_name != NULL) {
12174 if (caller == NULL)
12176 if (caller->name.find(caller_name) == std::string::npos)
12180 // It matches add the invocation count to the tally.
12181 invocations += it->second;
12184 return invocations;
12188 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
12189 v8::HandleScope outer(isolate);
12190 v8::Local<Context> env = Context::New(isolate);
12193 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
12194 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
12195 env->Global()->Set(v8_str("obj"), t->NewInstance());
12197 const char* script =
12198 "function bar() {\n"
12200 " for (i = 0; i < 100; ++i)\n"
12204 "function foo(i) { return i * i; }\n"
12205 "// Invoke on the runtime function.\n"
12207 CompileRun(script);
12208 bar_func_ = i::Handle<i::JSFunction>::cast(
12209 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
12210 DCHECK(!bar_func_.is_null());
12213 i::Handle<i::JSFunction>::cast(
12214 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
12215 DCHECK(!foo_func_.is_null());
12217 v8::Handle<v8::Value> value = CompileRun("bar();");
12218 CHECK(value->IsNumber());
12219 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12221 // Test the optimized codegen path.
12222 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
12224 CHECK(value->IsNumber());
12225 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12231 void SetFunctionEntryHookTest::RunTest() {
12232 // Work in a new isolate throughout.
12233 v8::Isolate::CreateParams create_params;
12234 create_params.entry_hook = EntryHook;
12235 create_params.code_event_handler = JitEvent;
12236 v8::Isolate* isolate = v8::Isolate::New(create_params);
12239 v8::Isolate::Scope scope(isolate);
12241 RunLoopInNewEnv(isolate);
12243 // Check the exepected invocation counts.
12244 CHECK_EQ(2, CountInvocations(NULL, "bar"));
12245 CHECK_EQ(200, CountInvocations("bar", "foo"));
12246 CHECK_EQ(200, CountInvocations(NULL, "foo"));
12248 // Verify that we have an entry hook on some specific stubs.
12249 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
12250 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
12251 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
12253 isolate->Dispose();
12257 // Make sure a second isolate is unaffected by the previous entry hook.
12258 isolate = v8::Isolate::New();
12260 v8::Isolate::Scope scope(isolate);
12262 // Reset the entry count to zero and set the entry hook.
12263 RunLoopInNewEnv(isolate);
12265 // We should record no invocations in this isolate.
12266 CHECK_EQ(0, static_cast<int>(invocations_.size()));
12269 isolate->Dispose();
12273 TEST(SetFunctionEntryHook) {
12274 // FunctionEntryHook does not work well with experimental natives.
12275 // Experimental natives are compiled during snapshot deserialization.
12276 // This test breaks because InstallGetter (function from snapshot that
12277 // only gets called from experimental natives) is compiled with entry hooks.
12278 i::FLAG_allow_natives_syntax = true;
12279 i::FLAG_use_inlining = false;
12281 SetFunctionEntryHookTest test;
12286 static i::HashMap* code_map = NULL;
12287 static i::HashMap* jitcode_line_info = NULL;
12288 static int saw_bar = 0;
12289 static int move_events = 0;
12292 static bool FunctionNameIs(const char* expected,
12293 const v8::JitCodeEvent* event) {
12294 // Log lines for functions are of the general form:
12295 // "LazyCompile:<type><function_name>", where the type is one of
12297 static const char kPreamble[] = "LazyCompile:";
12298 static size_t kPreambleLen = sizeof(kPreamble) - 1;
12300 if (event->name.len < sizeof(kPreamble) - 1 ||
12301 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
12305 const char* tail = event->name.str + kPreambleLen;
12306 size_t tail_len = event->name.len - kPreambleLen;
12307 size_t expected_len = strlen(expected);
12308 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
12313 // Check for tails like 'bar :1'.
12314 if (tail_len > expected_len + 2 &&
12315 tail[expected_len] == ' ' &&
12316 tail[expected_len + 1] == ':' &&
12317 tail[expected_len + 2] &&
12318 !strncmp(tail, expected, expected_len)) {
12322 if (tail_len != expected_len)
12325 return strncmp(tail, expected, expected_len) == 0;
12329 static void event_handler(const v8::JitCodeEvent* event) {
12330 CHECK(event != NULL);
12331 CHECK(code_map != NULL);
12332 CHECK(jitcode_line_info != NULL);
12334 class DummyJitCodeLineInfo {
12337 switch (event->type) {
12338 case v8::JitCodeEvent::CODE_ADDED: {
12339 CHECK(event->code_start != NULL);
12340 CHECK_NE(0, static_cast<int>(event->code_len));
12341 CHECK(event->name.str != NULL);
12342 i::HashMap::Entry* entry =
12343 code_map->Lookup(event->code_start,
12344 i::ComputePointerHash(event->code_start),
12346 entry->value = reinterpret_cast<void*>(event->code_len);
12348 if (FunctionNameIs("bar", event)) {
12354 case v8::JitCodeEvent::CODE_MOVED: {
12355 uint32_t hash = i::ComputePointerHash(event->code_start);
12356 // We would like to never see code move that we haven't seen before,
12357 // but the code creation event does not happen until the line endings
12358 // have been calculated (this is so that we can report the line in the
12359 // script at which the function source is found, see
12360 // Compiler::RecordFunctionCompilation) and the line endings
12361 // calculations can cause a GC, which can move the newly created code
12362 // before its existence can be logged.
12363 i::HashMap::Entry* entry =
12364 code_map->Lookup(event->code_start, hash, false);
12365 if (entry != NULL) {
12368 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
12369 code_map->Remove(event->code_start, hash);
12371 entry = code_map->Lookup(event->new_code_start,
12372 i::ComputePointerHash(event->new_code_start),
12374 CHECK(entry != NULL);
12375 entry->value = reinterpret_cast<void*>(event->code_len);
12380 case v8::JitCodeEvent::CODE_REMOVED:
12381 // Object/code removal events are currently not dispatched from the GC.
12385 // For CODE_START_LINE_INFO_RECORDING event, we will create one
12386 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
12387 // record it in jitcode_line_info.
12388 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
12389 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
12390 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
12391 temp_event->user_data = line_info;
12392 i::HashMap::Entry* entry =
12393 jitcode_line_info->Lookup(line_info,
12394 i::ComputePointerHash(line_info),
12396 entry->value = reinterpret_cast<void*>(line_info);
12399 // For these two events, we will check whether the event->user_data
12400 // data structure is created before during CODE_START_LINE_INFO_RECORDING
12401 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
12402 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
12403 CHECK(event->user_data != NULL);
12404 uint32_t hash = i::ComputePointerHash(event->user_data);
12405 i::HashMap::Entry* entry =
12406 jitcode_line_info->Lookup(event->user_data, hash, false);
12407 CHECK(entry != NULL);
12408 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
12412 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
12413 CHECK(event->user_data != NULL);
12414 uint32_t hash = i::ComputePointerHash(event->user_data);
12415 i::HashMap::Entry* entry =
12416 jitcode_line_info->Lookup(event->user_data, hash, false);
12417 CHECK(entry != NULL);
12422 // Impossible event.
12429 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
12430 i::FLAG_stress_compaction = true;
12431 i::FLAG_incremental_marking = false;
12432 if (i::FLAG_never_compact) return;
12433 const char* script =
12436 " for (i = 0; i < 10; ++i)"
12440 "function foo(i) { return i; };"
12443 // Run this test in a new isolate to make sure we don't
12444 // have remnants of state from other code.
12445 v8::Isolate* isolate = v8::Isolate::New();
12447 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
12448 i::Heap* heap = i_isolate->heap();
12450 // Start with a clean slate.
12451 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Prepare");
12454 v8::HandleScope scope(isolate);
12455 i::HashMap code(MatchPointers);
12458 i::HashMap lineinfo(MatchPointers);
12459 jitcode_line_info = &lineinfo;
12464 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
12466 // Generate new code objects sparsely distributed across several
12467 // different fragmented code-space pages.
12468 const int kIterations = 10;
12469 for (int i = 0; i < kIterations; ++i) {
12470 LocalContext env(isolate);
12471 i::AlwaysAllocateScope always_allocate(i_isolate);
12472 SimulateFullSpace(heap->code_space());
12473 CompileRun(script);
12475 // Keep a strong reference to the code object in the handle scope.
12476 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
12477 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
12478 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
12479 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
12481 // Clear the compilation cache to get more wastage.
12482 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
12485 // Force code movement.
12486 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Move");
12488 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
12490 CHECK_LE(kIterations, saw_bar);
12491 CHECK_LT(0, move_events);
12494 jitcode_line_info = NULL;
12498 isolate->Dispose();
12500 // Do this in a new isolate.
12501 isolate = v8::Isolate::New();
12504 // Verify that we get callbacks for existing code objects when we
12505 // request enumeration of existing code.
12507 v8::HandleScope scope(isolate);
12508 LocalContext env(isolate);
12509 CompileRun(script);
12511 // Now get code through initial iteration.
12512 i::HashMap code(MatchPointers);
12515 i::HashMap lineinfo(MatchPointers);
12516 jitcode_line_info = &lineinfo;
12518 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
12520 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
12522 jitcode_line_info = NULL;
12523 // We expect that we got some events. Note that if we could get code removal
12524 // notifications, we could compare two collections, one created by listening
12525 // from the time of creation of an isolate, and the other by subscribing
12526 // with EnumExisting.
12527 CHECK_LT(0u, code.occupancy());
12533 isolate->Dispose();
12537 THREADED_TEST(ExternalAllocatedMemory) {
12538 v8::Isolate* isolate = CcTest::isolate();
12539 v8::HandleScope outer(isolate);
12540 v8::Local<Context> env(Context::New(isolate));
12541 CHECK(!env.IsEmpty());
12542 const int64_t kSize = 1024*1024;
12543 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
12544 CHECK_EQ(baseline + kSize,
12545 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
12547 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
12548 const int64_t kTriggerGCSize =
12549 v8::internal::Internals::kExternalAllocationLimit + 1;
12550 CHECK_EQ(baseline + kTriggerGCSize,
12551 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
12553 isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
12557 // Regression test for issue 54, object templates with internal fields
12558 // but no accessors or interceptors did not get their internal field
12559 // count set on instances.
12560 THREADED_TEST(Regress54) {
12561 LocalContext context;
12562 v8::Isolate* isolate = context->GetIsolate();
12563 v8::HandleScope outer(isolate);
12564 static v8::Persistent<v8::ObjectTemplate> templ;
12565 if (templ.IsEmpty()) {
12566 v8::EscapableHandleScope inner(isolate);
12567 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
12568 local->SetInternalFieldCount(1);
12569 templ.Reset(isolate, inner.Escape(local));
12571 v8::Handle<v8::Object> result =
12572 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
12573 CHECK_EQ(1, result->InternalFieldCount());
12577 // If part of the threaded tests, this test makes ThreadingTest fail
12579 TEST(CatchStackOverflow) {
12580 LocalContext context;
12581 v8::HandleScope scope(context->GetIsolate());
12582 v8::TryCatch try_catch;
12583 v8::Handle<v8::Value> result = CompileRun(
12589 CHECK(result.IsEmpty());
12593 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
12594 const char* resource_name,
12596 v8::HandleScope scope(CcTest::isolate());
12597 v8::TryCatch try_catch;
12598 v8::Handle<v8::Value> result = script->Run();
12599 CHECK(result.IsEmpty());
12600 CHECK(try_catch.HasCaught());
12601 v8::Handle<v8::Message> message = try_catch.Message();
12602 CHECK(!message.IsEmpty());
12603 CHECK_EQ(10 + line_offset, message->GetLineNumber());
12604 CHECK_EQ(91, message->GetStartPosition());
12605 CHECK_EQ(92, message->GetEndPosition());
12606 CHECK_EQ(2, message->GetStartColumn());
12607 CHECK_EQ(3, message->GetEndColumn());
12608 v8::String::Utf8Value line(message->GetSourceLine());
12609 CHECK_EQ(0, strcmp(" throw 'nirk';", *line));
12610 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
12611 CHECK_EQ(0, strcmp(resource_name, *name));
12615 THREADED_TEST(TryCatchSourceInfo) {
12616 LocalContext context;
12617 v8::HandleScope scope(context->GetIsolate());
12618 v8::Local<v8::String> source = v8_str(
12619 "function Foo() {\n"
12623 "function Bar() {\n"
12627 "function Baz() {\n"
12633 const char* resource_name;
12634 v8::Handle<v8::Script> script;
12635 resource_name = "test.js";
12636 script = CompileWithOrigin(source, resource_name);
12637 CheckTryCatchSourceInfo(script, resource_name, 0);
12639 resource_name = "test1.js";
12640 v8::ScriptOrigin origin1(
12641 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
12642 script = v8::Script::Compile(source, &origin1);
12643 CheckTryCatchSourceInfo(script, resource_name, 0);
12645 resource_name = "test2.js";
12646 v8::ScriptOrigin origin2(
12647 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
12648 v8::Integer::New(context->GetIsolate(), 7));
12649 script = v8::Script::Compile(source, &origin2);
12650 CheckTryCatchSourceInfo(script, resource_name, 7);
12654 THREADED_TEST(CompilationCache) {
12655 LocalContext context;
12656 v8::HandleScope scope(context->GetIsolate());
12657 v8::Handle<v8::String> source0 =
12658 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
12659 v8::Handle<v8::String> source1 =
12660 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
12661 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
12662 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
12663 v8::Handle<v8::Script> script2 =
12664 v8::Script::Compile(source0); // different origin
12665 CHECK_EQ(1234, script0->Run()->Int32Value());
12666 CHECK_EQ(1234, script1->Run()->Int32Value());
12667 CHECK_EQ(1234, script2->Run()->Int32Value());
12671 static void FunctionNameCallback(
12672 const v8::FunctionCallbackInfo<v8::Value>& args) {
12673 ApiTestFuzzer::Fuzz();
12674 args.GetReturnValue().Set(v8_num(42));
12678 THREADED_TEST(CallbackFunctionName) {
12679 LocalContext context;
12680 v8::Isolate* isolate = context->GetIsolate();
12681 v8::HandleScope scope(isolate);
12682 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
12683 t->Set(v8_str("asdf"),
12684 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
12685 context->Global()->Set(v8_str("obj"), t->NewInstance());
12686 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
12687 CHECK(value->IsString());
12688 v8::String::Utf8Value name(value);
12689 CHECK_EQ(0, strcmp("asdf", *name));
12693 THREADED_TEST(DateAccess) {
12694 LocalContext context;
12695 v8::HandleScope scope(context->GetIsolate());
12696 v8::Handle<v8::Value> date =
12697 v8::Date::New(context->GetIsolate(), 1224744689038.0);
12698 CHECK(date->IsDate());
12699 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
12703 void CheckProperties(v8::Isolate* isolate, v8::Handle<v8::Value> val,
12704 unsigned elmc, const char* elmv[]) {
12705 v8::Handle<v8::Object> obj = val.As<v8::Object>();
12706 v8::Handle<v8::Array> props = obj->GetPropertyNames();
12707 CHECK_EQ(elmc, props->Length());
12708 for (unsigned i = 0; i < elmc; i++) {
12709 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
12710 CHECK_EQ(0, strcmp(elmv[i], *elm));
12715 void CheckOwnProperties(v8::Isolate* isolate, v8::Handle<v8::Value> val,
12716 unsigned elmc, const char* elmv[]) {
12717 v8::Handle<v8::Object> obj = val.As<v8::Object>();
12718 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
12719 CHECK_EQ(elmc, props->Length());
12720 for (unsigned i = 0; i < elmc; i++) {
12721 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
12722 CHECK_EQ(0, strcmp(elmv[i], *elm));
12727 THREADED_TEST(PropertyEnumeration) {
12728 LocalContext context;
12729 v8::Isolate* isolate = context->GetIsolate();
12730 v8::HandleScope scope(isolate);
12731 v8::Handle<v8::Value> obj = CompileRun(
12734 "result[1] = {a: 1, b: 2};"
12735 "result[2] = [1, 2, 3];"
12736 "var proto = {x: 1, y: 2, z: 3};"
12737 "var x = { __proto__: proto, w: 0, z: 1 };"
12740 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12741 CHECK_EQ(4u, elms->Length());
12743 const char** elmv0 = NULL;
12745 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12746 CheckOwnProperties(
12747 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12749 const char* elmv1[] = {"a", "b"};
12751 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
12752 CheckOwnProperties(
12753 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
12755 const char* elmv2[] = {"0", "1", "2"};
12757 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
12758 CheckOwnProperties(
12759 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
12761 const char* elmv3[] = {"w", "z", "x", "y"};
12763 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
12765 const char* elmv4[] = {"w", "z"};
12766 CheckOwnProperties(
12767 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
12771 THREADED_TEST(PropertyEnumeration2) {
12772 LocalContext context;
12773 v8::Isolate* isolate = context->GetIsolate();
12774 v8::HandleScope scope(isolate);
12775 v8::Handle<v8::Value> obj = CompileRun(
12778 "result[1] = {a: 1, b: 2};"
12779 "result[2] = [1, 2, 3];"
12780 "var proto = {x: 1, y: 2, z: 3};"
12781 "var x = { __proto__: proto, w: 0, z: 1 };"
12784 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12785 CHECK_EQ(4u, elms->Length());
12787 const char** elmv0 = NULL;
12788 CheckProperties(isolate,
12789 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12791 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
12792 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
12793 CHECK_EQ(0u, props->Length());
12794 for (uint32_t i = 0; i < props->Length(); i++) {
12795 printf("p[%u]\n", i);
12800 THREADED_TEST(AccessChecksReenabledCorrectly) {
12801 LocalContext context;
12802 v8::Isolate* isolate = context->GetIsolate();
12803 v8::HandleScope scope(isolate);
12804 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
12805 templ->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
12806 templ->Set(v8_str("a"), v8_str("a"));
12807 // Add more than 8 (see kMaxFastProperties) properties
12808 // so that the constructor will force copying map.
12809 // Cannot sprintf, gcc complains unsafety.
12811 for (char i = '0'; i <= '9' ; i++) {
12813 for (char j = '0'; j <= '9'; j++) {
12815 for (char k = '0'; k <= '9'; k++) {
12818 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
12823 Local<v8::Object> instance_1 = templ->NewInstance();
12824 context->Global()->Set(v8_str("obj_1"), instance_1);
12826 Local<Value> value_1 = CompileRun("obj_1.a");
12827 CHECK(value_1.IsEmpty());
12829 Local<v8::Object> instance_2 = templ->NewInstance();
12830 context->Global()->Set(v8_str("obj_2"), instance_2);
12832 Local<Value> value_2 = CompileRun("obj_2.a");
12833 CHECK(value_2.IsEmpty());
12837 THREADED_TEST(TurnOnAccessCheck) {
12838 v8::Isolate* isolate = CcTest::isolate();
12839 v8::HandleScope handle_scope(isolate);
12841 // Create an environment with access check to the global object disabled by
12843 v8::Handle<v8::ObjectTemplate> global_template =
12844 v8::ObjectTemplate::New(isolate);
12845 global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL,
12846 v8::Handle<v8::Value>(), false);
12847 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
12848 Context::Scope context_scope(context);
12850 // Set up a property and a number of functions.
12851 context->Global()->Set(v8_str("a"), v8_num(1));
12852 CompileRun("function f1() {return a;}"
12853 "function f2() {return a;}"
12854 "function g1() {return h();}"
12855 "function g2() {return h();}"
12856 "function h() {return 1;}");
12857 Local<Function> f1 =
12858 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12859 Local<Function> f2 =
12860 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12861 Local<Function> g1 =
12862 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12863 Local<Function> g2 =
12864 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12865 Local<Function> h =
12866 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
12868 // Get the global object.
12869 v8::Handle<v8::Object> global = context->Global();
12871 // Call f1 one time and f2 a number of times. This will ensure that f1 still
12872 // uses the runtime system to retreive property a whereas f2 uses global load
12874 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
12875 for (int i = 0; i < 4; i++) {
12876 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12879 // Same for g1 and g2.
12880 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12881 for (int i = 0; i < 4; i++) {
12882 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12885 // Detach the global and turn on access check.
12886 Local<Object> hidden_global = Local<Object>::Cast(
12887 context->Global()->GetPrototype());
12888 context->DetachGlobal();
12889 hidden_global->TurnOnAccessCheck();
12891 // Failing access check results in exception.
12892 CHECK(f1->Call(global, 0, NULL).IsEmpty());
12893 CHECK(f2->Call(global, 0, NULL).IsEmpty());
12894 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12895 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12897 // No failing access check when just returning a constant.
12898 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12902 // Tests that ScriptData can be serialized and deserialized.
12903 TEST(PreCompileSerialization) {
12904 v8::V8::Initialize();
12906 v8::Isolate* isolate = env->GetIsolate();
12907 HandleScope handle_scope(isolate);
12909 i::FLAG_min_preparse_length = 0;
12910 const char* script = "function foo(a) { return a+1; }";
12911 v8::ScriptCompiler::Source source(v8_str(script));
12912 v8::ScriptCompiler::Compile(isolate, &source,
12913 v8::ScriptCompiler::kProduceParserCache);
12915 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
12916 i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
12917 i::MemCopy(serialized_data, cd->data, cd->length);
12920 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
12922 // Verify that the original is the same as the deserialized.
12923 CHECK_EQ(cd->length, deserialized->length());
12924 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
12926 delete deserialized;
12927 i::DeleteArray(serialized_data);
12931 // This tests that we do not allow dictionary load/call inline caches
12932 // to use functions that have not yet been compiled. The potential
12933 // problem of loading a function that has not yet been compiled can
12934 // arise because we share code between contexts via the compilation
12936 THREADED_TEST(DictionaryICLoadedFunction) {
12937 v8::HandleScope scope(CcTest::isolate());
12939 for (int i = 0; i < 2; i++) {
12940 LocalContext context;
12941 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
12942 context->Global()->Delete(v8_str("tmp"));
12943 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
12946 for (int i = 0; i < 2; i++) {
12947 LocalContext context;
12948 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
12949 context->Global()->Delete(v8_str("tmp"));
12950 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
12955 // Test that cross-context new calls use the context of the callee to
12956 // create the new JavaScript object.
12957 THREADED_TEST(CrossContextNew) {
12958 v8::Isolate* isolate = CcTest::isolate();
12959 v8::HandleScope scope(isolate);
12960 v8::Local<Context> context0 = Context::New(isolate);
12961 v8::Local<Context> context1 = Context::New(isolate);
12963 // Allow cross-domain access.
12964 Local<String> token = v8_str("<security token>");
12965 context0->SetSecurityToken(token);
12966 context1->SetSecurityToken(token);
12968 // Set an 'x' property on the Object prototype and define a
12969 // constructor function in context0.
12971 CompileRun("Object.prototype.x = 42; function C() {};");
12974 // Call the constructor function from context0 and check that the
12975 // result has the 'x' property.
12977 context1->Global()->Set(v8_str("other"), context0->Global());
12978 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
12979 CHECK(value->IsInt32());
12980 CHECK_EQ(42, value->Int32Value());
12985 // Verify that we can clone an object
12986 TEST(ObjectClone) {
12988 v8::Isolate* isolate = env->GetIsolate();
12989 v8::HandleScope scope(isolate);
12991 const char* sample =
12993 "rv.alpha = 'hello';" \
12997 // Create an object, verify basics.
12998 Local<Value> val = CompileRun(sample);
12999 CHECK(val->IsObject());
13000 Local<v8::Object> obj = val.As<v8::Object>();
13001 obj->Set(v8_str("gamma"), v8_str("cloneme"));
13003 CHECK(v8_str("hello")->Equals(obj->Get(v8_str("alpha"))));
13004 CHECK(v8::Integer::New(isolate, 123)->Equals(obj->Get(v8_str("beta"))));
13005 CHECK(v8_str("cloneme")->Equals(obj->Get(v8_str("gamma"))));
13008 Local<v8::Object> clone = obj->Clone();
13009 CHECK(v8_str("hello")->Equals(clone->Get(v8_str("alpha"))));
13010 CHECK(v8::Integer::New(isolate, 123)->Equals(clone->Get(v8_str("beta"))));
13011 CHECK(v8_str("cloneme")->Equals(clone->Get(v8_str("gamma"))));
13013 // Set a property on the clone, verify each object.
13014 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
13015 CHECK(v8::Integer::New(isolate, 123)->Equals(obj->Get(v8_str("beta"))));
13016 CHECK(v8::Integer::New(isolate, 456)->Equals(clone->Get(v8_str("beta"))));
13020 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
13022 explicit OneByteVectorResource(i::Vector<const char> vector)
13024 virtual ~OneByteVectorResource() {}
13025 virtual size_t length() const { return data_.length(); }
13026 virtual const char* data() const { return data_.start(); }
13028 i::Vector<const char> data_;
13032 class UC16VectorResource : public v8::String::ExternalStringResource {
13034 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
13036 virtual ~UC16VectorResource() {}
13037 virtual size_t length() const { return data_.length(); }
13038 virtual const i::uc16* data() const { return data_.start(); }
13040 i::Vector<const i::uc16> data_;
13044 static void MorphAString(i::String* string,
13045 OneByteVectorResource* one_byte_resource,
13046 UC16VectorResource* uc16_resource) {
13047 CHECK(i::StringShape(string).IsExternal());
13048 if (string->IsOneByteRepresentation()) {
13049 // Check old map is not internalized or long.
13050 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
13051 // Morph external string to be TwoByte string.
13052 string->set_map(CcTest::heap()->external_string_map());
13053 i::ExternalTwoByteString* morphed =
13054 i::ExternalTwoByteString::cast(string);
13055 morphed->set_resource(uc16_resource);
13057 // Check old map is not internalized or long.
13058 CHECK(string->map() == CcTest::heap()->external_string_map());
13059 // Morph external string to be one-byte string.
13060 string->set_map(CcTest::heap()->external_one_byte_string_map());
13061 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
13062 morphed->set_resource(one_byte_resource);
13067 // Test that we can still flatten a string if the components it is built up
13068 // from have been turned into 16 bit strings in the mean time.
13069 THREADED_TEST(MorphCompositeStringTest) {
13070 char utf_buffer[129];
13071 const char* c_string = "Now is the time for all good men"
13072 " to come to the aid of the party";
13073 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
13076 i::Factory* factory = CcTest::i_isolate()->factory();
13077 v8::HandleScope scope(env->GetIsolate());
13078 OneByteVectorResource one_byte_resource(
13079 i::Vector<const char>(c_string, i::StrLength(c_string)));
13080 UC16VectorResource uc16_resource(
13081 i::Vector<const uint16_t>(two_byte_string,
13082 i::StrLength(c_string)));
13085 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
13086 &one_byte_resource).ToHandleChecked()));
13088 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
13089 &one_byte_resource).ToHandleChecked()));
13091 env->Global()->Set(v8_str("lhs"), lhs);
13092 env->Global()->Set(v8_str("rhs"), rhs);
13095 "var cons = lhs + rhs;"
13096 "var slice = lhs.substring(1, lhs.length - 1);"
13097 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
13099 CHECK(lhs->IsOneByte());
13100 CHECK(rhs->IsOneByte());
13102 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
13104 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
13107 // This should UTF-8 without flattening, since everything is ASCII.
13108 Handle<String> cons = v8_compile("cons")->Run().As<String>();
13109 CHECK_EQ(128, cons->Utf8Length());
13111 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
13112 CHECK_EQ(128, nchars);
13113 CHECK_EQ(0, strcmp(
13115 "Now is the time for all good men to come to the aid of the party"
13116 "Now is the time for all good men to come to the aid of the party"));
13118 // Now do some stuff to make sure the strings are flattened, etc.
13120 "/[^a-z]/.test(cons);"
13121 "/[^a-z]/.test(slice);"
13122 "/[^a-z]/.test(slice_on_cons);");
13123 const char* expected_cons =
13124 "Now is the time for all good men to come to the aid of the party"
13125 "Now is the time for all good men to come to the aid of the party";
13126 const char* expected_slice =
13127 "ow is the time for all good men to come to the aid of the part";
13128 const char* expected_slice_on_cons =
13129 "ow is the time for all good men to come to the aid of the party"
13130 "Now is the time for all good men to come to the aid of the part";
13131 CHECK(String::NewFromUtf8(env->GetIsolate(), expected_cons)
13132 ->Equals(env->Global()->Get(v8_str("cons"))));
13133 CHECK(String::NewFromUtf8(env->GetIsolate(), expected_slice)
13134 ->Equals(env->Global()->Get(v8_str("slice"))));
13135 CHECK(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons)
13136 ->Equals(env->Global()->Get(v8_str("slice_on_cons"))));
13138 i::DeleteArray(two_byte_string);
13142 TEST(CompileExternalTwoByteSource) {
13143 LocalContext context;
13144 v8::HandleScope scope(context->GetIsolate());
13146 // This is a very short list of sources, which currently is to check for a
13147 // regression caused by r2703.
13148 const char* one_byte_sources[] = {
13150 "-0.5", // This mainly testes PushBack in the Scanner.
13151 "--0.5", // This mainly testes PushBack in the Scanner.
13154 // Compile the sources as external two byte strings.
13155 for (int i = 0; one_byte_sources[i] != NULL; i++) {
13156 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
13157 TestResource* uc16_resource = new TestResource(two_byte_string);
13158 v8::Local<v8::String> source =
13159 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
13160 v8::Script::Compile(source);
13165 #ifndef V8_INTERPRETED_REGEXP
13167 struct RegExpInterruptionData {
13168 v8::base::Atomic32 loop_count;
13169 UC16VectorResource* string_resource;
13170 v8::Persistent<v8::String> string;
13171 } regexp_interruption_data;
13174 class RegExpInterruptionThread : public v8::base::Thread {
13176 explicit RegExpInterruptionThread(v8::Isolate* isolate)
13177 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
13179 virtual void Run() {
13180 for (v8::base::NoBarrier_Store(®exp_interruption_data.loop_count, 0);
13181 v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) < 7;
13182 v8::base::NoBarrier_AtomicIncrement(
13183 ®exp_interruption_data.loop_count, 1)) {
13184 v8::base::OS::Sleep(50); // Wait a bit before requesting GC.
13185 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
13187 v8::base::OS::Sleep(50); // Wait a bit before terminating.
13188 v8::V8::TerminateExecution(isolate_);
13192 v8::Isolate* isolate_;
13196 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
13197 if (v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) != 2) {
13200 v8::HandleScope scope(CcTest::isolate());
13201 v8::Local<v8::String> string = v8::Local<v8::String>::New(
13202 CcTest::isolate(), regexp_interruption_data.string);
13203 string->MakeExternal(regexp_interruption_data.string_resource);
13207 // Test that RegExp execution can be interrupted. Specifically, we test
13208 // * interrupting with GC
13209 // * turn the subject string from one-byte internal to two-byte external string
13210 // * force termination
13211 TEST(RegExpInterruption) {
13212 v8::HandleScope scope(CcTest::isolate());
13215 RegExpInterruptionThread timeout_thread(CcTest::isolate());
13217 v8::V8::AddGCPrologueCallback(RunBeforeGC);
13218 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
13219 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
13220 v8::Local<v8::String> string = v8_str(one_byte_content);
13222 CcTest::global()->Set(v8_str("a"), string);
13223 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
13224 regexp_interruption_data.string_resource = new UC16VectorResource(
13225 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
13227 v8::TryCatch try_catch;
13228 timeout_thread.Start();
13230 CompileRun("/((a*)*)*b/.exec(a)");
13231 CHECK(try_catch.HasTerminated());
13233 timeout_thread.Join();
13235 regexp_interruption_data.string.Reset();
13236 i::DeleteArray(uc16_content);
13239 #endif // V8_INTERPRETED_REGEXP
13242 // Test that we cannot set a property on the global object if there
13243 // is a read-only property in the prototype chain.
13244 TEST(ReadOnlyPropertyInGlobalProto) {
13245 v8::Isolate* isolate = CcTest::isolate();
13246 v8::HandleScope scope(isolate);
13247 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13248 LocalContext context(0, templ);
13249 v8::Handle<v8::Object> global = context->Global();
13250 v8::Handle<v8::Object> global_proto =
13251 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
13252 global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
13254 global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
13256 // Check without 'eval' or 'with'.
13257 v8::Handle<v8::Value> res =
13258 CompileRun("function f() { x = 42; return x; }; f()");
13259 CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13260 // Check with 'eval'.
13261 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
13262 CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13263 // Check with 'with'.
13264 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
13265 CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13268 static int force_set_set_count = 0;
13269 static int force_set_get_count = 0;
13270 bool pass_on_get = false;
13272 static void ForceSetGetter(v8::Local<v8::String> name,
13273 const v8::PropertyCallbackInfo<v8::Value>& info) {
13274 force_set_get_count++;
13278 info.GetReturnValue().Set(3);
13281 static void ForceSetSetter(v8::Local<v8::String> name,
13282 v8::Local<v8::Value> value,
13283 const v8::PropertyCallbackInfo<void>& info) {
13284 force_set_set_count++;
13287 static void ForceSetInterceptGetter(
13288 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13289 CHECK(name->IsString());
13290 ForceSetGetter(Local<String>::Cast(name), info);
13293 static void ForceSetInterceptSetter(
13294 v8::Local<v8::Name> name, v8::Local<v8::Value> value,
13295 const v8::PropertyCallbackInfo<v8::Value>& info) {
13296 force_set_set_count++;
13297 info.GetReturnValue().SetUndefined();
13302 force_set_get_count = 0;
13303 force_set_set_count = 0;
13304 pass_on_get = false;
13306 v8::Isolate* isolate = CcTest::isolate();
13307 v8::HandleScope scope(isolate);
13308 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13309 v8::Handle<v8::String> access_property =
13310 v8::String::NewFromUtf8(isolate, "a");
13311 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
13312 LocalContext context(NULL, templ);
13313 v8::Handle<v8::Object> global = context->Global();
13315 // Ordinary properties
13316 v8::Handle<v8::String> simple_property =
13317 v8::String::NewFromUtf8(isolate, "p");
13318 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
13319 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13320 // This should fail because the property is read-only
13321 global->Set(simple_property, v8::Int32::New(isolate, 5));
13322 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13323 // This should succeed even though the property is read-only
13324 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
13325 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
13328 CHECK_EQ(0, force_set_set_count);
13329 CHECK_EQ(0, force_set_get_count);
13330 CHECK_EQ(3, global->Get(access_property)->Int32Value());
13331 // CHECK_EQ the property shouldn't override it, just call the setter
13332 // which in this case does nothing.
13333 global->Set(access_property, v8::Int32::New(isolate, 7));
13334 CHECK_EQ(3, global->Get(access_property)->Int32Value());
13335 CHECK_EQ(1, force_set_set_count);
13336 CHECK_EQ(2, force_set_get_count);
13337 // Forcing the property to be set should override the accessor without
13339 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
13340 CHECK_EQ(8, global->Get(access_property)->Int32Value());
13341 CHECK_EQ(1, force_set_set_count);
13342 CHECK_EQ(2, force_set_get_count);
13346 TEST(ForceSetWithInterceptor) {
13347 force_set_get_count = 0;
13348 force_set_set_count = 0;
13349 pass_on_get = false;
13351 v8::Isolate* isolate = CcTest::isolate();
13352 v8::HandleScope scope(isolate);
13353 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13354 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13355 ForceSetInterceptGetter, ForceSetInterceptSetter));
13356 LocalContext context(NULL, templ);
13357 v8::Handle<v8::Object> global = context->Global();
13359 v8::Handle<v8::String> some_property =
13360 v8::String::NewFromUtf8(isolate, "a");
13361 CHECK_EQ(0, force_set_set_count);
13362 CHECK_EQ(0, force_set_get_count);
13363 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13364 // Setting the property shouldn't override it, just call the setter
13365 // which in this case does nothing.
13366 global->Set(some_property, v8::Int32::New(isolate, 7));
13367 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13368 CHECK_EQ(1, force_set_set_count);
13369 CHECK_EQ(2, force_set_get_count);
13370 // Getting the property when the interceptor returns an empty handle
13371 // should yield undefined, since the property isn't present on the
13372 // object itself yet.
13373 pass_on_get = true;
13374 CHECK(global->Get(some_property)->IsUndefined());
13375 CHECK_EQ(1, force_set_set_count);
13376 CHECK_EQ(3, force_set_get_count);
13377 // Forcing the property to be set should cause the value to be
13378 // set locally without calling the interceptor.
13379 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
13380 CHECK_EQ(8, global->Get(some_property)->Int32Value());
13381 CHECK_EQ(1, force_set_set_count);
13382 CHECK_EQ(4, force_set_get_count);
13383 // Reenabling the interceptor should cause it to take precedence over
13385 pass_on_get = false;
13386 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13387 CHECK_EQ(1, force_set_set_count);
13388 CHECK_EQ(5, force_set_get_count);
13389 // The interceptor should also work for other properties
13390 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
13392 CHECK_EQ(1, force_set_set_count);
13393 CHECK_EQ(6, force_set_get_count);
13397 static v8::Local<Context> calling_context0;
13398 static v8::Local<Context> calling_context1;
13399 static v8::Local<Context> calling_context2;
13402 // Check that the call to the callback is initiated in
13403 // calling_context2, the directly calling context is calling_context1
13404 // and the callback itself is in calling_context0.
13405 static void GetCallingContextCallback(
13406 const v8::FunctionCallbackInfo<v8::Value>& args) {
13407 ApiTestFuzzer::Fuzz();
13408 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
13409 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
13410 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
13411 args.GetReturnValue().Set(42);
13415 THREADED_TEST(GetCurrentContextWhenNotInContext) {
13416 i::Isolate* isolate = CcTest::i_isolate();
13417 CHECK(isolate != NULL);
13418 CHECK(isolate->context() == NULL);
13419 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
13420 v8::HandleScope scope(v8_isolate);
13421 // The following should not crash, but return an empty handle.
13422 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
13423 CHECK(current.IsEmpty());
13427 THREADED_TEST(GetCallingContext) {
13428 v8::Isolate* isolate = CcTest::isolate();
13429 v8::HandleScope scope(isolate);
13431 Local<Context> calling_context0(Context::New(isolate));
13432 Local<Context> calling_context1(Context::New(isolate));
13433 Local<Context> calling_context2(Context::New(isolate));
13434 ::calling_context0 = calling_context0;
13435 ::calling_context1 = calling_context1;
13436 ::calling_context2 = calling_context2;
13438 // Allow cross-domain access.
13439 Local<String> token = v8_str("<security token>");
13440 calling_context0->SetSecurityToken(token);
13441 calling_context1->SetSecurityToken(token);
13442 calling_context2->SetSecurityToken(token);
13444 // Create an object with a C++ callback in context0.
13445 calling_context0->Enter();
13446 Local<v8::FunctionTemplate> callback_templ =
13447 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
13448 calling_context0->Global()->Set(v8_str("callback"),
13449 callback_templ->GetFunction());
13450 calling_context0->Exit();
13452 // Expose context0 in context1 and set up a function that calls the
13453 // callback function.
13454 calling_context1->Enter();
13455 calling_context1->Global()->Set(v8_str("context0"),
13456 calling_context0->Global());
13457 CompileRun("function f() { context0.callback() }");
13458 calling_context1->Exit();
13460 // Expose context1 in context2 and call the callback function in
13461 // context0 indirectly through f in context1.
13462 calling_context2->Enter();
13463 calling_context2->Global()->Set(v8_str("context1"),
13464 calling_context1->Global());
13465 CompileRun("context1.f()");
13466 calling_context2->Exit();
13467 ::calling_context0.Clear();
13468 ::calling_context1.Clear();
13469 ::calling_context2.Clear();
13473 // Check that a variable declaration with no explicit initialization
13474 // value does shadow an existing property in the prototype chain.
13475 THREADED_TEST(InitGlobalVarInProtoChain) {
13476 LocalContext context;
13477 v8::HandleScope scope(context->GetIsolate());
13478 // Introduce a variable in the prototype chain.
13479 CompileRun("__proto__.x = 42");
13480 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
13481 CHECK(!result->IsUndefined());
13482 CHECK_EQ(43, result->Int32Value());
13486 // Regression test for issue 398.
13487 // If a function is added to an object, creating a constant function
13488 // field, and the result is cloned, replacing the constant function on the
13489 // original should not affect the clone.
13490 // See http://code.google.com/p/v8/issues/detail?id=398
13491 THREADED_TEST(ReplaceConstantFunction) {
13492 LocalContext context;
13493 v8::Isolate* isolate = context->GetIsolate();
13494 v8::HandleScope scope(isolate);
13495 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
13496 v8::Handle<v8::FunctionTemplate> func_templ =
13497 v8::FunctionTemplate::New(isolate);
13498 v8::Handle<v8::String> foo_string =
13499 v8::String::NewFromUtf8(isolate, "foo");
13500 obj->Set(foo_string, func_templ->GetFunction());
13501 v8::Handle<v8::Object> obj_clone = obj->Clone();
13502 obj_clone->Set(foo_string,
13503 v8::String::NewFromUtf8(isolate, "Hello"));
13504 CHECK(!obj->Get(foo_string)->IsUndefined());
13508 static void CheckElementValue(i::Isolate* isolate,
13510 i::Handle<i::Object> obj,
13512 i::Object* element =
13513 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
13514 CHECK_EQ(expected, i::Smi::cast(element)->value());
13518 THREADED_TEST(PixelArray) {
13519 LocalContext context;
13520 i::Isolate* isolate = CcTest::i_isolate();
13521 i::Factory* factory = isolate->factory();
13522 v8::HandleScope scope(context->GetIsolate());
13523 const int kElementCount = 260;
13524 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
13525 i::Handle<i::ExternalUint8ClampedArray> pixels =
13526 i::Handle<i::ExternalUint8ClampedArray>::cast(
13527 factory->NewExternalArray(kElementCount,
13528 v8::kExternalUint8ClampedArray,
13530 // Force GC to trigger verification.
13531 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13532 for (int i = 0; i < kElementCount; i++) {
13533 pixels->set(i, i % 256);
13535 // Force GC to trigger verification.
13536 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13537 for (int i = 0; i < kElementCount; i++) {
13538 CHECK_EQ(i % 256, pixels->get_scalar(i));
13539 CHECK_EQ(i % 256, pixel_data[i]);
13542 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
13543 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13544 // Set the elements to be the pixels.
13545 // jsobj->set_elements(*pixels);
13546 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13547 CheckElementValue(isolate, 1, jsobj, 1);
13548 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
13549 context->Global()->Set(v8_str("pixels"), obj);
13550 v8::Handle<v8::Value> result = CompileRun("pixels.field");
13551 CHECK_EQ(1503, result->Int32Value());
13552 result = CompileRun("pixels[1]");
13553 CHECK_EQ(1, result->Int32Value());
13555 result = CompileRun("var sum = 0;"
13556 "for (var i = 0; i < 8; i++) {"
13557 " sum += pixels[i] = pixels[i] = -i;"
13560 CHECK_EQ(-28, result->Int32Value());
13562 result = CompileRun("var sum = 0;"
13563 "for (var i = 0; i < 8; i++) {"
13564 " sum += pixels[i] = pixels[i] = 0;"
13567 CHECK_EQ(0, result->Int32Value());
13569 result = CompileRun("var sum = 0;"
13570 "for (var i = 0; i < 8; i++) {"
13571 " sum += pixels[i] = pixels[i] = 255;"
13574 CHECK_EQ(8 * 255, result->Int32Value());
13576 result = CompileRun("var sum = 0;"
13577 "for (var i = 0; i < 8; i++) {"
13578 " sum += pixels[i] = pixels[i] = 256 + i;"
13581 CHECK_EQ(2076, result->Int32Value());
13583 result = CompileRun("var sum = 0;"
13584 "for (var i = 0; i < 8; i++) {"
13585 " sum += pixels[i] = pixels[i] = i;"
13588 CHECK_EQ(28, result->Int32Value());
13590 result = CompileRun("var sum = 0;"
13591 "for (var i = 0; i < 8; i++) {"
13592 " sum += pixels[i];"
13595 CHECK_EQ(28, result->Int32Value());
13597 i::Handle<i::Smi> value(i::Smi::FromInt(2),
13598 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
13599 i::Handle<i::Object> no_failure;
13600 no_failure = i::JSObject::SetElement(
13601 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
13602 DCHECK(!no_failure.is_null());
13604 CheckElementValue(isolate, 2, jsobj, 1);
13605 *value.location() = i::Smi::FromInt(256);
13606 no_failure = i::JSObject::SetElement(
13607 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
13608 DCHECK(!no_failure.is_null());
13610 CheckElementValue(isolate, 255, jsobj, 1);
13611 *value.location() = i::Smi::FromInt(-1);
13612 no_failure = i::JSObject::SetElement(
13613 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
13614 DCHECK(!no_failure.is_null());
13616 CheckElementValue(isolate, 0, jsobj, 1);
13618 result = CompileRun("for (var i = 0; i < 8; i++) {"
13619 " pixels[i] = (i * 65) - 109;"
13621 "pixels[1] + pixels[6];");
13622 CHECK_EQ(255, result->Int32Value());
13623 CheckElementValue(isolate, 0, jsobj, 0);
13624 CheckElementValue(isolate, 0, jsobj, 1);
13625 CheckElementValue(isolate, 21, jsobj, 2);
13626 CheckElementValue(isolate, 86, jsobj, 3);
13627 CheckElementValue(isolate, 151, jsobj, 4);
13628 CheckElementValue(isolate, 216, jsobj, 5);
13629 CheckElementValue(isolate, 255, jsobj, 6);
13630 CheckElementValue(isolate, 255, jsobj, 7);
13631 result = CompileRun("var sum = 0;"
13632 "for (var i = 0; i < 8; i++) {"
13633 " sum += pixels[i];"
13636 CHECK_EQ(984, result->Int32Value());
13638 result = CompileRun("for (var i = 0; i < 8; i++) {"
13639 " pixels[i] = (i * 1.1);"
13641 "pixels[1] + pixels[6];");
13642 CHECK_EQ(8, result->Int32Value());
13643 CheckElementValue(isolate, 0, jsobj, 0);
13644 CheckElementValue(isolate, 1, jsobj, 1);
13645 CheckElementValue(isolate, 2, jsobj, 2);
13646 CheckElementValue(isolate, 3, jsobj, 3);
13647 CheckElementValue(isolate, 4, jsobj, 4);
13648 CheckElementValue(isolate, 6, jsobj, 5);
13649 CheckElementValue(isolate, 7, jsobj, 6);
13650 CheckElementValue(isolate, 8, jsobj, 7);
13652 result = CompileRun("for (var i = 0; i < 8; i++) {"
13653 " pixels[7] = undefined;"
13656 CHECK_EQ(0, result->Int32Value());
13657 CheckElementValue(isolate, 0, jsobj, 7);
13659 result = CompileRun("for (var i = 0; i < 8; i++) {"
13660 " pixels[6] = '2.3';"
13663 CHECK_EQ(2, result->Int32Value());
13664 CheckElementValue(isolate, 2, jsobj, 6);
13666 result = CompileRun("for (var i = 0; i < 8; i++) {"
13667 " pixels[5] = NaN;"
13670 CHECK_EQ(0, result->Int32Value());
13671 CheckElementValue(isolate, 0, jsobj, 5);
13673 result = CompileRun("for (var i = 0; i < 8; i++) {"
13674 " pixels[8] = Infinity;"
13677 CHECK_EQ(255, result->Int32Value());
13678 CheckElementValue(isolate, 255, jsobj, 8);
13680 result = CompileRun("for (var i = 0; i < 8; i++) {"
13681 " pixels[9] = -Infinity;"
13684 CHECK_EQ(0, result->Int32Value());
13685 CheckElementValue(isolate, 0, jsobj, 9);
13687 result = CompileRun("pixels[3] = 33;"
13688 "delete pixels[3];"
13690 CHECK_EQ(33, result->Int32Value());
13692 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13693 "pixels[2] = 12; pixels[3] = 13;"
13694 "pixels.__defineGetter__('2',"
13695 "function() { return 120; });"
13697 CHECK_EQ(12, result->Int32Value());
13699 result = CompileRun("var js_array = new Array(40);"
13700 "js_array[0] = 77;"
13702 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13704 result = CompileRun("pixels[1] = 23;"
13705 "pixels.__proto__ = [];"
13706 "js_array.__proto__ = pixels;"
13707 "js_array.concat(pixels);");
13708 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13709 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13711 result = CompileRun("pixels[1] = 23;");
13712 CHECK_EQ(23, result->Int32Value());
13714 // Test for index greater than 255. Regression test for:
13715 // http://code.google.com/p/chromium/issues/detail?id=26337.
13716 result = CompileRun("pixels[256] = 255;");
13717 CHECK_EQ(255, result->Int32Value());
13718 result = CompileRun("var i = 0;"
13719 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
13721 CHECK_EQ(255, result->Int32Value());
13723 // Make sure that pixel array ICs recognize when a non-pixel array
13724 // is passed to it.
13725 result = CompileRun("function pa_load(p) {"
13727 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13730 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13731 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13732 "just_ints = new Object();"
13733 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13734 "for (var i = 0; i < 10; ++i) {"
13735 " result = pa_load(just_ints);"
13738 CHECK_EQ(32640, result->Int32Value());
13740 // Make sure that pixel array ICs recognize out-of-bound accesses.
13741 result = CompileRun("function pa_load(p, start) {"
13743 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13746 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13747 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13748 "for (var i = 0; i < 10; ++i) {"
13749 " result = pa_load(pixels,-10);"
13752 CHECK_EQ(0, result->Int32Value());
13754 // Make sure that generic ICs properly handles a pixel array.
13755 result = CompileRun("function pa_load(p) {"
13757 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13760 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13761 "just_ints = new Object();"
13762 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13763 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13764 "for (var i = 0; i < 10; ++i) {"
13765 " result = pa_load(pixels);"
13768 CHECK_EQ(32640, result->Int32Value());
13770 // Make sure that generic load ICs recognize out-of-bound accesses in
13772 result = CompileRun("function pa_load(p, start) {"
13774 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13777 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13778 "just_ints = new Object();"
13779 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13780 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
13781 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13782 "for (var i = 0; i < 10; ++i) {"
13783 " result = pa_load(pixels,-10);"
13786 CHECK_EQ(0, result->Int32Value());
13788 // Make sure that generic ICs properly handles other types than pixel
13789 // arrays (that the inlined fast pixel array test leaves the right information
13790 // in the right registers).
13791 result = CompileRun("function pa_load(p) {"
13793 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13796 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13797 "just_ints = new Object();"
13798 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13799 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13800 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13801 "sparse_array = new Object();"
13802 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
13803 "sparse_array[1000000] = 3;"
13804 "for (var i = 0; i < 10; ++i) {"
13805 " result = pa_load(sparse_array);"
13808 CHECK_EQ(32640, result->Int32Value());
13810 // Make sure that pixel array store ICs clamp values correctly.
13811 result = CompileRun("function pa_store(p) {"
13812 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13814 "pa_store(pixels);"
13816 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13818 CHECK_EQ(48896, result->Int32Value());
13820 // Make sure that pixel array stores correctly handle accesses outside
13821 // of the pixel array..
13822 result = CompileRun("function pa_store(p,start) {"
13823 " for (var j = 0; j < 256; j++) {"
13824 " p[j+start] = j * 2;"
13827 "pa_store(pixels,0);"
13828 "pa_store(pixels,-128);"
13830 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13832 CHECK_EQ(65280, result->Int32Value());
13834 // Make sure that the generic store stub correctly handle accesses outside
13835 // of the pixel array..
13836 result = CompileRun("function pa_store(p,start) {"
13837 " for (var j = 0; j < 256; j++) {"
13838 " p[j+start] = j * 2;"
13841 "pa_store(pixels,0);"
13842 "just_ints = new Object();"
13843 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13844 "pa_store(just_ints, 0);"
13845 "pa_store(pixels,-128);"
13847 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13849 CHECK_EQ(65280, result->Int32Value());
13851 // Make sure that the generic keyed store stub clamps pixel array values
13853 result = CompileRun("function pa_store(p) {"
13854 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13856 "pa_store(pixels);"
13857 "just_ints = new Object();"
13858 "pa_store(just_ints);"
13859 "pa_store(pixels);"
13861 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13863 CHECK_EQ(48896, result->Int32Value());
13865 // Make sure that pixel array loads are optimized by crankshaft.
13866 result = CompileRun("function pa_load(p) {"
13868 " for (var i=0; i<256; ++i) {"
13873 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13874 "for (var i = 0; i < 5000; ++i) {"
13875 " result = pa_load(pixels);"
13878 CHECK_EQ(32640, result->Int32Value());
13880 // Make sure that pixel array stores are optimized by crankshaft.
13881 result = CompileRun("function pa_init(p) {"
13882 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
13884 "function pa_load(p) {"
13886 " for (var i=0; i<256; ++i) {"
13891 "for (var i = 0; i < 5000; ++i) {"
13892 " pa_init(pixels);"
13894 "result = pa_load(pixels);"
13896 CHECK_EQ(32640, result->Int32Value());
13902 THREADED_TEST(PixelArrayInfo) {
13903 LocalContext context;
13904 v8::HandleScope scope(context->GetIsolate());
13905 for (int size = 0; size < 100; size += 10) {
13906 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
13907 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
13908 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
13909 CHECK(obj->HasIndexedPropertiesInPixelData());
13910 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
13911 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
13917 static void NotHandledIndexedPropertyGetter(
13919 const v8::PropertyCallbackInfo<v8::Value>& info) {
13920 ApiTestFuzzer::Fuzz();
13924 static void NotHandledIndexedPropertySetter(
13926 Local<Value> value,
13927 const v8::PropertyCallbackInfo<v8::Value>& info) {
13928 ApiTestFuzzer::Fuzz();
13932 THREADED_TEST(PixelArrayWithInterceptor) {
13933 LocalContext context;
13934 i::Factory* factory = CcTest::i_isolate()->factory();
13935 v8::Isolate* isolate = context->GetIsolate();
13936 v8::HandleScope scope(isolate);
13937 const int kElementCount = 260;
13938 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
13939 i::Handle<i::ExternalUint8ClampedArray> pixels =
13940 i::Handle<i::ExternalUint8ClampedArray>::cast(
13941 factory->NewExternalArray(kElementCount,
13942 v8::kExternalUint8ClampedArray,
13944 for (int i = 0; i < kElementCount; i++) {
13945 pixels->set(i, i % 256);
13947 v8::Handle<v8::ObjectTemplate> templ =
13948 v8::ObjectTemplate::New(context->GetIsolate());
13949 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
13950 NotHandledIndexedPropertyGetter, NotHandledIndexedPropertySetter));
13951 v8::Handle<v8::Object> obj = templ->NewInstance();
13952 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13953 context->Global()->Set(v8_str("pixels"), obj);
13954 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
13955 CHECK_EQ(1, result->Int32Value());
13956 result = CompileRun("var sum = 0;"
13957 "for (var i = 0; i < 8; i++) {"
13958 " sum += pixels[i] = pixels[i] = -i;"
13961 CHECK_EQ(-28, result->Int32Value());
13962 result = CompileRun("pixels.hasOwnProperty('1')");
13963 CHECK(result->BooleanValue());
13968 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
13969 switch (array_type) {
13970 case v8::kExternalInt8Array:
13971 case v8::kExternalUint8Array:
13972 case v8::kExternalUint8ClampedArray:
13975 case v8::kExternalInt16Array:
13976 case v8::kExternalUint16Array:
13979 case v8::kExternalInt32Array:
13980 case v8::kExternalUint32Array:
13981 case v8::kExternalFloat32Array:
13984 case v8::kExternalFloat64Array:
13996 template <class ExternalArrayClass, class ElementType>
13997 static void ObjectWithExternalArrayTestHelper(
13998 Handle<Context> context,
13999 v8::Handle<Object> obj,
14001 v8::ExternalArrayType array_type,
14002 int64_t low, int64_t high) {
14003 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14004 i::Isolate* isolate = jsobj->GetIsolate();
14005 obj->Set(v8_str("field"),
14006 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
14007 context->Global()->Set(v8_str("ext_array"), obj);
14008 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
14009 CHECK_EQ(1503, result->Int32Value());
14010 result = CompileRun("ext_array[1]");
14011 CHECK_EQ(1, result->Int32Value());
14013 // Check assigned smis
14014 result = CompileRun("for (var i = 0; i < 8; i++) {"
14015 " ext_array[i] = i;"
14018 "for (var i = 0; i < 8; i++) {"
14019 " sum += ext_array[i];"
14023 CHECK_EQ(28, result->Int32Value());
14024 // Check pass through of assigned smis
14025 result = CompileRun("var sum = 0;"
14026 "for (var i = 0; i < 8; i++) {"
14027 " sum += ext_array[i] = ext_array[i] = -i;"
14030 CHECK_EQ(-28, result->Int32Value());
14033 // Check assigned smis in reverse order
14034 result = CompileRun("for (var i = 8; --i >= 0; ) {"
14035 " ext_array[i] = i;"
14038 "for (var i = 0; i < 8; i++) {"
14039 " sum += ext_array[i];"
14042 CHECK_EQ(28, result->Int32Value());
14044 // Check pass through of assigned HeapNumbers
14045 result = CompileRun("var sum = 0;"
14046 "for (var i = 0; i < 16; i+=2) {"
14047 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
14050 CHECK_EQ(-28, result->Int32Value());
14052 // Check assigned HeapNumbers
14053 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
14054 " ext_array[i] = (i * 0.5);"
14057 "for (var i = 0; i < 16; i+=2) {"
14058 " sum += ext_array[i];"
14061 CHECK_EQ(28, result->Int32Value());
14063 // Check assigned HeapNumbers in reverse order
14064 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
14065 " ext_array[i] = (i * 0.5);"
14068 "for (var i = 0; i < 16; i+=2) {"
14069 " sum += ext_array[i];"
14072 CHECK_EQ(28, result->Int32Value());
14074 i::ScopedVector<char> test_buf(1024);
14076 // Check legal boundary conditions.
14077 // The repeated loads and stores ensure the ICs are exercised.
14078 const char* boundary_program =
14080 "for (var i = 0; i < 16; i++) {"
14081 " ext_array[i] = %lld;"
14083 " res = ext_array[i];"
14087 i::SNPrintF(test_buf,
14090 result = CompileRun(test_buf.start());
14091 CHECK_EQ(low, result->IntegerValue());
14093 i::SNPrintF(test_buf,
14096 result = CompileRun(test_buf.start());
14097 CHECK_EQ(high, result->IntegerValue());
14099 // Check misprediction of type in IC.
14100 result = CompileRun("var tmp_array = ext_array;"
14102 "for (var i = 0; i < 8; i++) {"
14103 " tmp_array[i] = i;"
14104 " sum += tmp_array[i];"
14110 // Force GC to trigger verification.
14111 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14112 CHECK_EQ(28, result->Int32Value());
14114 // Make sure out-of-range loads do not throw.
14115 i::SNPrintF(test_buf,
14116 "var caught_exception = false;"
14120 " caught_exception = true;"
14122 "caught_exception;",
14124 result = CompileRun(test_buf.start());
14125 CHECK_EQ(false, result->BooleanValue());
14127 // Make sure out-of-range stores do not throw.
14128 i::SNPrintF(test_buf,
14129 "var caught_exception = false;"
14131 " ext_array[%d] = 1;"
14133 " caught_exception = true;"
14135 "caught_exception;",
14137 result = CompileRun(test_buf.start());
14138 CHECK_EQ(false, result->BooleanValue());
14140 // Check other boundary conditions, values and operations.
14141 result = CompileRun("for (var i = 0; i < 8; i++) {"
14142 " ext_array[7] = undefined;"
14145 CHECK_EQ(0, result->Int32Value());
14146 if (array_type == v8::kExternalFloat64Array ||
14147 array_type == v8::kExternalFloat32Array) {
14149 i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
14151 CheckElementValue(isolate, 0, jsobj, 7);
14154 result = CompileRun("for (var i = 0; i < 8; i++) {"
14155 " ext_array[6] = '2.3';"
14158 CHECK_EQ(2, result->Int32Value());
14161 i::Object::GetElement(
14162 isolate, jsobj, 6).ToHandleChecked()->Number()));
14164 if (array_type != v8::kExternalFloat32Array &&
14165 array_type != v8::kExternalFloat64Array) {
14166 // Though the specification doesn't state it, be explicit about
14167 // converting NaNs and +/-Infinity to zero.
14168 result = CompileRun("for (var i = 0; i < 8; i++) {"
14169 " ext_array[i] = 5;"
14171 "for (var i = 0; i < 8; i++) {"
14172 " ext_array[i] = NaN;"
14175 CHECK_EQ(0, result->Int32Value());
14176 CheckElementValue(isolate, 0, jsobj, 5);
14178 result = CompileRun("for (var i = 0; i < 8; i++) {"
14179 " ext_array[i] = 5;"
14181 "for (var i = 0; i < 8; i++) {"
14182 " ext_array[i] = Infinity;"
14185 int expected_value =
14186 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
14187 CHECK_EQ(expected_value, result->Int32Value());
14188 CheckElementValue(isolate, expected_value, jsobj, 5);
14190 result = CompileRun("for (var i = 0; i < 8; i++) {"
14191 " ext_array[i] = 5;"
14193 "for (var i = 0; i < 8; i++) {"
14194 " ext_array[i] = -Infinity;"
14197 CHECK_EQ(0, result->Int32Value());
14198 CheckElementValue(isolate, 0, jsobj, 5);
14200 // Check truncation behavior of integral arrays.
14201 const char* unsigned_data =
14202 "var source_data = [0.6, 10.6];"
14203 "var expected_results = [0, 10];";
14204 const char* signed_data =
14205 "var source_data = [0.6, 10.6, -0.6, -10.6];"
14206 "var expected_results = [0, 10, 0, -10];";
14207 const char* pixel_data =
14208 "var source_data = [0.6, 10.6];"
14209 "var expected_results = [1, 11];";
14211 (array_type == v8::kExternalUint8Array ||
14212 array_type == v8::kExternalUint16Array ||
14213 array_type == v8::kExternalUint32Array);
14214 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
14216 i::SNPrintF(test_buf,
14218 "var all_passed = true;"
14219 "for (var i = 0; i < source_data.length; i++) {"
14220 " for (var j = 0; j < 8; j++) {"
14221 " ext_array[j] = source_data[i];"
14223 " all_passed = all_passed &&"
14224 " (ext_array[5] == expected_results[i]);"
14229 (is_pixel_data ? pixel_data : signed_data)));
14230 result = CompileRun(test_buf.start());
14231 CHECK_EQ(true, result->BooleanValue());
14234 i::Handle<ExternalArrayClass> array(
14235 ExternalArrayClass::cast(jsobj->elements()));
14236 for (int i = 0; i < element_count; i++) {
14237 array->set(i, static_cast<ElementType>(i));
14240 // Test complex assignments
14241 result = CompileRun("function ee_op_test_complex_func(sum) {"
14242 " for (var i = 0; i < 40; ++i) {"
14243 " sum += (ext_array[i] += 1);"
14244 " sum += (ext_array[i] -= 1);"
14249 "for (var i=0;i<10000;++i) {"
14250 " sum=ee_op_test_complex_func(sum);"
14253 CHECK_EQ(16000000, result->Int32Value());
14255 // Test count operations
14256 result = CompileRun("function ee_op_test_count_func(sum) {"
14257 " for (var i = 0; i < 40; ++i) {"
14258 " sum += (++ext_array[i]);"
14259 " sum += (--ext_array[i]);"
14264 "for (var i=0;i<10000;++i) {"
14265 " sum=ee_op_test_count_func(sum);"
14268 CHECK_EQ(16000000, result->Int32Value());
14270 result = CompileRun("ext_array[3] = 33;"
14271 "delete ext_array[3];"
14273 CHECK_EQ(33, result->Int32Value());
14275 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
14276 "ext_array[2] = 12; ext_array[3] = 13;"
14277 "ext_array.__defineGetter__('2',"
14278 "function() { return 120; });"
14280 CHECK_EQ(12, result->Int32Value());
14282 result = CompileRun("var js_array = new Array(40);"
14283 "js_array[0] = 77;"
14285 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14287 result = CompileRun("ext_array[1] = 23;"
14288 "ext_array.__proto__ = [];"
14289 "js_array.__proto__ = ext_array;"
14290 "js_array.concat(ext_array);");
14291 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14292 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
14294 result = CompileRun("ext_array[1] = 23;");
14295 CHECK_EQ(23, result->Int32Value());
14299 template <class FixedTypedArrayClass,
14300 i::ElementsKind elements_kind,
14302 static void FixedTypedArrayTestHelper(
14303 v8::ExternalArrayType array_type,
14305 ElementType high) {
14306 i::FLAG_allow_natives_syntax = true;
14307 LocalContext context;
14308 i::Isolate* isolate = CcTest::i_isolate();
14309 i::Factory* factory = isolate->factory();
14310 v8::HandleScope scope(context->GetIsolate());
14311 const int kElementCount = 260;
14312 i::Handle<FixedTypedArrayClass> fixed_array =
14313 i::Handle<FixedTypedArrayClass>::cast(
14314 factory->NewFixedTypedArray(kElementCount, array_type));
14315 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
14316 fixed_array->map()->instance_type());
14317 CHECK_EQ(kElementCount, fixed_array->length());
14318 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14319 for (int i = 0; i < kElementCount; i++) {
14320 fixed_array->set(i, static_cast<ElementType>(i));
14322 // Force GC to trigger verification.
14323 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14324 for (int i = 0; i < kElementCount; i++) {
14325 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
14326 static_cast<int64_t>(fixed_array->get_scalar(i)));
14328 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
14329 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14330 i::Handle<i::Map> fixed_array_map =
14331 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
14332 jsobj->set_map(*fixed_array_map);
14333 jsobj->set_elements(*fixed_array);
14335 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
14336 context.local(), obj, kElementCount, array_type,
14337 static_cast<int64_t>(low),
14338 static_cast<int64_t>(high));
14342 THREADED_TEST(FixedUint8Array) {
14343 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
14344 v8::kExternalUint8Array,
14349 THREADED_TEST(FixedUint8ClampedArray) {
14350 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
14351 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
14352 v8::kExternalUint8ClampedArray,
14357 THREADED_TEST(FixedInt8Array) {
14358 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
14359 v8::kExternalInt8Array,
14364 THREADED_TEST(FixedUint16Array) {
14365 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
14366 v8::kExternalUint16Array,
14371 THREADED_TEST(FixedInt16Array) {
14372 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
14373 v8::kExternalInt16Array,
14378 THREADED_TEST(FixedUint32Array) {
14379 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
14380 v8::kExternalUint32Array,
14385 THREADED_TEST(FixedInt32Array) {
14386 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
14387 v8::kExternalInt32Array,
14392 THREADED_TEST(FixedFloat32Array) {
14393 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
14394 v8::kExternalFloat32Array,
14399 THREADED_TEST(FixedFloat64Array) {
14400 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
14401 v8::kExternalFloat64Array,
14406 template <class ExternalArrayClass, class ElementType>
14407 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
14410 LocalContext context;
14411 i::Isolate* isolate = CcTest::i_isolate();
14412 i::Factory* factory = isolate->factory();
14413 v8::HandleScope scope(context->GetIsolate());
14414 const int kElementCount = 40;
14415 int element_size = ExternalArrayElementSize(array_type);
14416 ElementType* array_data =
14417 static_cast<ElementType*>(malloc(kElementCount * element_size));
14418 i::Handle<ExternalArrayClass> array =
14419 i::Handle<ExternalArrayClass>::cast(
14420 factory->NewExternalArray(kElementCount, array_type, array_data));
14421 // Force GC to trigger verification.
14422 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14423 for (int i = 0; i < kElementCount; i++) {
14424 array->set(i, static_cast<ElementType>(i));
14426 // Force GC to trigger verification.
14427 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14428 for (int i = 0; i < kElementCount; i++) {
14429 CHECK_EQ(static_cast<int64_t>(i),
14430 static_cast<int64_t>(array->get_scalar(i)));
14431 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
14434 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
14435 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14436 // Set the elements to be the external array.
14437 obj->SetIndexedPropertiesToExternalArrayData(array_data,
14442 i::Object::GetElement(
14443 isolate, jsobj, 1).ToHandleChecked()->Number()));
14445 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
14446 context.local(), obj, kElementCount, array_type, low, high);
14448 v8::Handle<v8::Value> result;
14450 // Test more complex manipulations which cause eax to contain values
14451 // that won't be completely overwritten by loads from the arrays.
14452 // This catches bugs in the instructions used for the KeyedLoadIC
14453 // for byte and word types.
14455 const int kXSize = 300;
14456 const int kYSize = 300;
14457 const int kLargeElementCount = kXSize * kYSize * 4;
14458 ElementType* large_array_data =
14459 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
14460 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
14461 // Set the elements to be the external array.
14462 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
14464 kLargeElementCount);
14465 context->Global()->Set(v8_str("large_array"), large_obj);
14466 // Initialize contents of a few rows.
14467 for (int x = 0; x < 300; x++) {
14469 int offset = row * 300 * 4;
14470 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14471 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14472 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14473 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14475 offset = row * 300 * 4;
14476 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14477 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14478 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14479 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14481 offset = row * 300 * 4;
14482 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14483 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14484 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14485 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14487 // The goal of the code below is to make "offset" large enough
14488 // that the computation of the index (which goes into eax) has
14489 // high bits set which will not be overwritten by a byte or short
14491 result = CompileRun("var failed = false;"
14493 "for (var i = 0; i < 300; i++) {"
14494 " if (large_array[4 * i] != 127 ||"
14495 " large_array[4 * i + 1] != 0 ||"
14496 " large_array[4 * i + 2] != 0 ||"
14497 " large_array[4 * i + 3] != 127) {"
14501 "offset = 150 * 300 * 4;"
14502 "for (var i = 0; i < 300; i++) {"
14503 " if (large_array[offset + 4 * i] != 127 ||"
14504 " large_array[offset + 4 * i + 1] != 0 ||"
14505 " large_array[offset + 4 * i + 2] != 0 ||"
14506 " large_array[offset + 4 * i + 3] != 127) {"
14510 "offset = 298 * 300 * 4;"
14511 "for (var i = 0; i < 300; i++) {"
14512 " if (large_array[offset + 4 * i] != 127 ||"
14513 " large_array[offset + 4 * i + 1] != 0 ||"
14514 " large_array[offset + 4 * i + 2] != 0 ||"
14515 " large_array[offset + 4 * i + 3] != 127) {"
14520 CHECK_EQ(true, result->BooleanValue());
14521 free(large_array_data);
14524 // The "" property descriptor is overloaded to store information about
14525 // the external array. Ensure that setting and accessing the "" property
14526 // works (it should overwrite the information cached about the external
14527 // array in the DescriptorArray) in various situations.
14528 result = CompileRun("ext_array[''] = 23; ext_array['']");
14529 CHECK_EQ(23, result->Int32Value());
14531 // Property "" set after the external array is associated with the object.
14533 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14534 obj2->Set(v8_str("ee_test_field"),
14535 v8::Int32::New(context->GetIsolate(), 256));
14536 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
14537 // Set the elements to be the external array.
14538 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14541 context->Global()->Set(v8_str("ext_array"), obj2);
14542 result = CompileRun("ext_array['']");
14543 CHECK_EQ(1503, result->Int32Value());
14546 // Property "" set after the external array is associated with the object.
14548 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14549 obj2->Set(v8_str("ee_test_field_2"),
14550 v8::Int32::New(context->GetIsolate(), 256));
14551 // Set the elements to be the external array.
14552 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14555 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
14556 context->Global()->Set(v8_str("ext_array"), obj2);
14557 result = CompileRun("ext_array['']");
14558 CHECK_EQ(1503, result->Int32Value());
14561 // Should reuse the map from previous test.
14563 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14564 obj2->Set(v8_str("ee_test_field_2"),
14565 v8::Int32::New(context->GetIsolate(), 256));
14566 // Set the elements to be the external array. Should re-use the map
14567 // from previous test.
14568 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14571 context->Global()->Set(v8_str("ext_array"), obj2);
14572 result = CompileRun("ext_array['']");
14575 // Property "" is a constant function that shouldn't not be interfered with
14576 // when an external array is set.
14578 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14580 obj2->Set(v8_str("ee_test_field3"),
14581 v8::Int32::New(context->GetIsolate(), 256));
14583 // Add a constant function to an object.
14584 context->Global()->Set(v8_str("ext_array"), obj2);
14585 result = CompileRun("ext_array[''] = function() {return 1503;};"
14586 "ext_array['']();");
14588 // Add an external array transition to the same map that
14589 // has the constant transition.
14590 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
14591 obj3->Set(v8_str("ee_test_field3"),
14592 v8::Int32::New(context->GetIsolate(), 256));
14593 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14596 context->Global()->Set(v8_str("ext_array"), obj3);
14599 // If a external array transition is in the map, it should get clobbered
14600 // by a constant function.
14602 // Add an external array transition.
14603 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
14604 obj3->Set(v8_str("ee_test_field4"),
14605 v8::Int32::New(context->GetIsolate(), 256));
14606 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14610 // Add a constant function to the same map that just got an external array
14612 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14613 obj2->Set(v8_str("ee_test_field4"),
14614 v8::Int32::New(context->GetIsolate(), 256));
14615 context->Global()->Set(v8_str("ext_array"), obj2);
14616 result = CompileRun("ext_array[''] = function() {return 1503;};"
14617 "ext_array['']();");
14624 THREADED_TEST(ExternalInt8Array) {
14625 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
14626 v8::kExternalInt8Array,
14632 THREADED_TEST(ExternalUint8Array) {
14633 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
14634 v8::kExternalUint8Array,
14640 THREADED_TEST(ExternalUint8ClampedArray) {
14641 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
14642 v8::kExternalUint8ClampedArray,
14648 THREADED_TEST(ExternalInt16Array) {
14649 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
14650 v8::kExternalInt16Array,
14656 THREADED_TEST(ExternalUint16Array) {
14657 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
14658 v8::kExternalUint16Array,
14664 THREADED_TEST(ExternalInt32Array) {
14665 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
14666 v8::kExternalInt32Array,
14667 INT_MIN, // -2147483648
14668 INT_MAX); // 2147483647
14672 THREADED_TEST(ExternalUint32Array) {
14673 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
14674 v8::kExternalUint32Array,
14676 UINT_MAX); // 4294967295
14680 THREADED_TEST(ExternalFloat32Array) {
14681 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
14682 v8::kExternalFloat32Array,
14688 THREADED_TEST(ExternalFloat64Array) {
14689 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
14690 v8::kExternalFloat64Array,
14696 THREADED_TEST(ExternalArrays) {
14697 TestExternalInt8Array();
14698 TestExternalUint8Array();
14699 TestExternalInt16Array();
14700 TestExternalUint16Array();
14701 TestExternalInt32Array();
14702 TestExternalUint32Array();
14703 TestExternalFloat32Array();
14707 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
14708 LocalContext context;
14709 v8::HandleScope scope(context->GetIsolate());
14710 for (int size = 0; size < 100; size += 10) {
14711 int element_size = ExternalArrayElementSize(array_type);
14712 void* external_data = malloc(size * element_size);
14713 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
14714 obj->SetIndexedPropertiesToExternalArrayData(
14715 external_data, array_type, size);
14716 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
14717 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
14718 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
14719 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
14720 free(external_data);
14725 THREADED_TEST(ExternalArrayInfo) {
14726 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
14727 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
14728 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
14729 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
14730 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
14731 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
14732 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
14733 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
14734 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
14738 void ExtArrayLimitsHelper(v8::Isolate* isolate,
14739 v8::ExternalArrayType array_type,
14741 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
14742 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14743 last_location = last_message = NULL;
14744 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
14745 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
14746 CHECK(last_location);
14747 CHECK(last_message);
14751 TEST(ExternalArrayLimits) {
14752 LocalContext context;
14753 v8::Isolate* isolate = context->GetIsolate();
14754 v8::HandleScope scope(isolate);
14755 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
14756 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
14757 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
14758 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
14759 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
14760 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
14761 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
14762 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
14763 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
14764 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
14765 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
14766 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
14767 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
14768 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
14769 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
14770 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
14771 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
14772 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
14776 template <typename ElementType, typename TypedArray,
14777 class ExternalArrayClass>
14778 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
14779 int64_t low, int64_t high) {
14780 const int kElementCount = 50;
14782 i::ScopedVector<ElementType> backing_store(kElementCount+2);
14785 v8::Isolate* isolate = env->GetIsolate();
14786 v8::HandleScope handle_scope(isolate);
14788 Local<v8::ArrayBuffer> ab =
14789 v8::ArrayBuffer::New(isolate, backing_store.start(),
14790 (kElementCount + 2) * sizeof(ElementType));
14791 Local<TypedArray> ta =
14792 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
14793 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
14794 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
14795 CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
14796 CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
14797 CHECK(ab->Equals(ta->Buffer()));
14799 ElementType* data = backing_store.start() + 2;
14800 for (int i = 0; i < kElementCount; i++) {
14801 data[i] = static_cast<ElementType>(i);
14804 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
14805 env.local(), ta, kElementCount, array_type, low, high);
14809 THREADED_TEST(Uint8Array) {
14810 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
14811 v8::kExternalUint8Array, 0, 0xFF);
14815 THREADED_TEST(Int8Array) {
14816 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
14817 v8::kExternalInt8Array, -0x80, 0x7F);
14821 THREADED_TEST(Uint16Array) {
14822 TypedArrayTestHelper<uint16_t,
14824 i::ExternalUint16Array>(
14825 v8::kExternalUint16Array, 0, 0xFFFF);
14829 THREADED_TEST(Int16Array) {
14830 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
14831 v8::kExternalInt16Array, -0x8000, 0x7FFF);
14835 THREADED_TEST(Uint32Array) {
14836 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
14837 v8::kExternalUint32Array, 0, UINT_MAX);
14841 THREADED_TEST(Int32Array) {
14842 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
14843 v8::kExternalInt32Array, INT_MIN, INT_MAX);
14847 THREADED_TEST(Float32Array) {
14848 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
14849 v8::kExternalFloat32Array, -500, 500);
14853 THREADED_TEST(Float64Array) {
14854 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
14855 v8::kExternalFloat64Array, -500, 500);
14859 THREADED_TEST(Uint8ClampedArray) {
14860 TypedArrayTestHelper<uint8_t,
14861 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
14862 v8::kExternalUint8ClampedArray, 0, 0xFF);
14866 THREADED_TEST(DataView) {
14867 const int kSize = 50;
14869 i::ScopedVector<uint8_t> backing_store(kSize+2);
14872 v8::Isolate* isolate = env->GetIsolate();
14873 v8::HandleScope handle_scope(isolate);
14875 Local<v8::ArrayBuffer> ab =
14876 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
14877 Local<v8::DataView> dv =
14878 v8::DataView::New(ab, 2, kSize);
14879 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
14880 CHECK_EQ(2u, dv->ByteOffset());
14881 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
14882 CHECK(ab->Equals(dv->Buffer()));
14886 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
14887 THREADED_TEST(Is##View) { \
14888 LocalContext env; \
14889 v8::Isolate* isolate = env->GetIsolate(); \
14890 v8::HandleScope handle_scope(isolate); \
14892 Handle<Value> result = CompileRun( \
14893 "var ab = new ArrayBuffer(128);" \
14894 "new " #View "(ab)"); \
14895 CHECK(result->IsArrayBufferView()); \
14896 CHECK(result->Is##View()); \
14897 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
14900 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
14901 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
14902 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
14903 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
14904 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
14905 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
14906 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
14907 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
14908 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
14909 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
14911 #undef IS_ARRAY_BUFFER_VIEW_TEST
14915 THREADED_TEST(ScriptContextDependence) {
14917 v8::HandleScope scope(c1->GetIsolate());
14918 const char *source = "foo";
14919 v8::Handle<v8::Script> dep = v8_compile(source);
14920 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
14921 c1->GetIsolate(), source));
14922 v8::Handle<v8::UnboundScript> indep =
14923 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
14924 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
14925 v8::Integer::New(c1->GetIsolate(), 100));
14926 CHECK_EQ(dep->Run()->Int32Value(), 100);
14927 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
14929 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
14930 v8::Integer::New(c2->GetIsolate(), 101));
14931 CHECK_EQ(dep->Run()->Int32Value(), 100);
14932 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
14936 THREADED_TEST(StackTrace) {
14937 LocalContext context;
14938 v8::HandleScope scope(context->GetIsolate());
14939 v8::TryCatch try_catch;
14940 const char *source = "function foo() { FAIL.FAIL; }; foo();";
14941 v8::Handle<v8::String> src =
14942 v8::String::NewFromUtf8(context->GetIsolate(), source);
14943 v8::Handle<v8::String> origin =
14944 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
14945 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
14946 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
14947 ->BindToCurrentContext()
14949 CHECK(try_catch.HasCaught());
14950 v8::String::Utf8Value stack(try_catch.StackTrace());
14951 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
14955 // Checks that a StackFrame has certain expected values.
14956 void checkStackFrame(const char* expected_script_name,
14957 const char* expected_func_name, int expected_line_number,
14958 int expected_column, bool is_eval, bool is_constructor,
14959 v8::Handle<v8::StackFrame> frame) {
14960 v8::HandleScope scope(CcTest::isolate());
14961 v8::String::Utf8Value func_name(frame->GetFunctionName());
14962 v8::String::Utf8Value script_name(frame->GetScriptName());
14963 if (*script_name == NULL) {
14964 // The situation where there is no associated script, like for evals.
14965 CHECK(expected_script_name == NULL);
14967 CHECK(strstr(*script_name, expected_script_name) != NULL);
14969 CHECK(strstr(*func_name, expected_func_name) != NULL);
14970 CHECK_EQ(expected_line_number, frame->GetLineNumber());
14971 CHECK_EQ(expected_column, frame->GetColumn());
14972 CHECK_EQ(is_eval, frame->IsEval());
14973 CHECK_EQ(is_constructor, frame->IsConstructor());
14977 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
14978 v8::HandleScope scope(args.GetIsolate());
14979 const char* origin = "capture-stack-trace-test";
14980 const int kOverviewTest = 1;
14981 const int kDetailedTest = 2;
14983 DCHECK(args.Length() == 1);
14985 int testGroup = args[0]->Int32Value();
14986 if (testGroup == kOverviewTest) {
14987 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
14988 args.GetIsolate(), 10, v8::StackTrace::kOverview);
14989 CHECK_EQ(4, stackTrace->GetFrameCount());
14990 checkStackFrame(origin, "bar", 2, 10, false, false,
14991 stackTrace->GetFrame(0));
14992 checkStackFrame(origin, "foo", 6, 3, false, false,
14993 stackTrace->GetFrame(1));
14994 // This is the source string inside the eval which has the call to foo.
14995 checkStackFrame(NULL, "", 1, 5, false, false,
14996 stackTrace->GetFrame(2));
14997 // The last frame is an anonymous function which has the initial eval call.
14998 checkStackFrame(origin, "", 8, 7, false, false,
14999 stackTrace->GetFrame(3));
15001 CHECK(stackTrace->AsArray()->IsArray());
15002 } else if (testGroup == kDetailedTest) {
15003 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15004 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15005 CHECK_EQ(4, stackTrace->GetFrameCount());
15006 checkStackFrame(origin, "bat", 4, 22, false, false,
15007 stackTrace->GetFrame(0));
15008 checkStackFrame(origin, "baz", 8, 3, false, true,
15009 stackTrace->GetFrame(1));
15010 bool is_eval = true;
15011 // This is the source string inside the eval which has the call to baz.
15012 checkStackFrame(NULL, "", 1, 5, is_eval, false,
15013 stackTrace->GetFrame(2));
15014 // The last frame is an anonymous function which has the initial eval call.
15015 checkStackFrame(origin, "", 10, 1, false, false,
15016 stackTrace->GetFrame(3));
15018 CHECK(stackTrace->AsArray()->IsArray());
15023 // Tests the C++ StackTrace API.
15024 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
15025 // THREADED_TEST(CaptureStackTrace) {
15026 TEST(CaptureStackTrace) {
15027 v8::Isolate* isolate = CcTest::isolate();
15028 v8::HandleScope scope(isolate);
15029 v8::Handle<v8::String> origin =
15030 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
15031 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15032 templ->Set(v8_str("AnalyzeStackInNativeCode"),
15033 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
15034 LocalContext context(0, templ);
15036 // Test getting OVERVIEW information. Should ignore information that is not
15037 // script name, function name, line number, and column offset.
15038 const char *overview_source =
15039 "function bar() {\n"
15040 " var y; AnalyzeStackInNativeCode(1);\n"
15042 "function foo() {\n"
15046 "var x;eval('new foo();');";
15047 v8::Handle<v8::String> overview_src =
15048 v8::String::NewFromUtf8(isolate, overview_source);
15049 v8::ScriptCompiler::Source script_source(overview_src,
15050 v8::ScriptOrigin(origin));
15051 v8::Handle<Value> overview_result(
15052 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
15053 ->BindToCurrentContext()
15055 CHECK(!overview_result.IsEmpty());
15056 CHECK(overview_result->IsObject());
15058 // Test getting DETAILED information.
15059 const char *detailed_source =
15060 "function bat() {AnalyzeStackInNativeCode(2);\n"
15063 "function baz() {\n"
15066 "eval('new baz();');";
15067 v8::Handle<v8::String> detailed_src =
15068 v8::String::NewFromUtf8(isolate, detailed_source);
15069 // Make the script using a non-zero line and column offset.
15070 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
15071 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
15072 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
15073 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
15074 v8::Handle<v8::UnboundScript> detailed_script(
15075 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
15076 v8::Handle<Value> detailed_result(
15077 detailed_script->BindToCurrentContext()->Run());
15078 CHECK(!detailed_result.IsEmpty());
15079 CHECK(detailed_result->IsObject());
15083 static void StackTraceForUncaughtExceptionListener(
15084 v8::Handle<v8::Message> message,
15085 v8::Handle<Value>) {
15087 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15088 CHECK_EQ(2, stack_trace->GetFrameCount());
15089 checkStackFrame("origin", "foo", 2, 3, false, false,
15090 stack_trace->GetFrame(0));
15091 checkStackFrame("origin", "bar", 5, 3, false, false,
15092 stack_trace->GetFrame(1));
15096 TEST(CaptureStackTraceForUncaughtException) {
15099 v8::HandleScope scope(env->GetIsolate());
15100 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
15101 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15103 CompileRunWithOrigin(
15104 "function foo() {\n"
15107 "function bar() {\n"
15111 v8::Local<v8::Object> global = env->Global();
15112 Local<Value> trouble = global->Get(v8_str("bar"));
15113 CHECK(trouble->IsFunction());
15114 Function::Cast(*trouble)->Call(global, 0, NULL);
15115 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15116 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
15117 CHECK_EQ(1, report_count);
15121 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
15124 v8::HandleScope scope(env->GetIsolate());
15126 // Create an Error object first.
15127 CompileRunWithOrigin(
15128 "function foo() {\n"
15129 "e=new Error('err');\n"
15131 "function bar() {\n"
15136 v8::Local<v8::Object> global = env->Global();
15137 Local<Value> trouble = global->Get(v8_str("bar"));
15138 CHECK(trouble->IsFunction());
15139 Function::Cast(*trouble)->Call(global, 0, NULL);
15141 // Enable capturing detailed stack trace late, and throw the exception.
15142 // The detailed stack trace should be extracted from the simple stack.
15143 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
15144 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15145 CompileRunWithOrigin("throw e", "origin");
15146 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15147 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
15148 CHECK_EQ(1, report_count);
15152 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
15154 v8::HandleScope scope(env->GetIsolate());
15155 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
15157 v8::StackTrace::kDetailed);
15160 "var setters = ['column', 'lineNumber', 'scriptName',\n"
15161 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
15162 " 'isConstructor'];\n"
15163 "for (var i = 0; i < setters.length; i++) {\n"
15164 " var prop = setters[i];\n"
15165 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
15167 CompileRun("throw 'exception';");
15168 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15172 static void StackTraceFunctionNameListener(v8::Handle<v8::Message> message,
15173 v8::Handle<Value>) {
15174 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15175 CHECK_EQ(5, stack_trace->GetFrameCount());
15176 checkStackFrame("origin", "foo:0", 4, 7, false, false,
15177 stack_trace->GetFrame(0));
15178 checkStackFrame("origin", "foo:1", 5, 27, false, false,
15179 stack_trace->GetFrame(1));
15180 checkStackFrame("origin", "foo", 5, 27, false, false,
15181 stack_trace->GetFrame(2));
15182 checkStackFrame("origin", "foo", 5, 27, false, false,
15183 stack_trace->GetFrame(3));
15184 checkStackFrame("origin", "", 1, 14, false, false, stack_trace->GetFrame(4));
15188 TEST(GetStackTraceContainsFunctionsWithFunctionName) {
15190 v8::HandleScope scope(env->GetIsolate());
15192 CompileRunWithOrigin(
15193 "function gen(name, counter) {\n"
15194 " var f = function foo() {\n"
15195 " if (counter === 0)\n"
15197 " gen(name, counter - 1)();\n"
15199 " if (counter == 3) {\n"
15200 " Object.defineProperty(f, 'name', {get: function(){ throw 239; }});\n"
15202 " Object.defineProperty(f, 'name', {writable:true});\n"
15203 " if (counter == 2)\n"
15206 " f.name = name + ':' + counter;\n"
15212 v8::V8::AddMessageListener(StackTraceFunctionNameListener);
15213 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15214 CompileRunWithOrigin("gen('foo', 3)();", "origin");
15215 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15216 v8::V8::RemoveMessageListeners(StackTraceFunctionNameListener);
15220 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
15221 v8::Handle<v8::Value> data) {
15222 // Use the frame where JavaScript is called from.
15223 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15224 CHECK(!stack_trace.IsEmpty());
15225 int frame_count = stack_trace->GetFrameCount();
15226 CHECK_EQ(3, frame_count);
15227 int line_number[] = {1, 2, 5};
15228 for (int i = 0; i < frame_count; i++) {
15229 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
15234 // Test that we only return the stack trace at the site where the exception
15235 // is first thrown (not where it is rethrown).
15236 TEST(RethrowStackTrace) {
15238 v8::HandleScope scope(env->GetIsolate());
15239 // We make sure that
15240 // - the stack trace of the ReferenceError in g() is reported.
15241 // - the stack trace is not overwritten when e1 is rethrown by t().
15242 // - the stack trace of e2 does not overwrite that of e1.
15243 const char* source =
15244 "function g() { error; } \n"
15245 "function f() { g(); } \n"
15246 "function t(e) { throw e; } \n"
15249 "} catch (e1) { \n"
15252 " } catch (e2) { \n"
15256 v8::V8::AddMessageListener(RethrowStackTraceHandler);
15257 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15258 CompileRun(source);
15259 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15260 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
15264 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
15265 v8::Handle<v8::Value> data) {
15266 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15267 CHECK(!stack_trace.IsEmpty());
15268 int frame_count = stack_trace->GetFrameCount();
15269 CHECK_EQ(2, frame_count);
15270 int line_number[] = {3, 7};
15271 for (int i = 0; i < frame_count; i++) {
15272 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
15277 // Test that we do not recognize identity for primitive exceptions.
15278 TEST(RethrowPrimitiveStackTrace) {
15280 v8::HandleScope scope(env->GetIsolate());
15281 // We do not capture stack trace for non Error objects on creation time.
15282 // Instead, we capture the stack trace on last throw.
15283 const char* source =
15284 "function g() { throw 404; } \n"
15285 "function f() { g(); } \n"
15286 "function t(e) { throw e; } \n"
15289 "} catch (e1) { \n"
15292 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
15293 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15294 CompileRun(source);
15295 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15296 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
15300 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
15301 v8::Handle<v8::Value> data) {
15302 // Use the frame where JavaScript is called from.
15303 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15304 CHECK(!stack_trace.IsEmpty());
15305 CHECK_EQ(1, stack_trace->GetFrameCount());
15306 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
15310 // Test that the stack trace is captured when the error object is created and
15311 // not where it is thrown.
15312 TEST(RethrowExistingStackTrace) {
15314 v8::HandleScope scope(env->GetIsolate());
15315 const char* source =
15316 "var e = new Error(); \n"
15318 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
15319 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15320 CompileRun(source);
15321 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15322 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
15326 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
15327 v8::Handle<v8::Value> data) {
15328 // Use the frame where JavaScript is called from.
15329 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15330 CHECK(!stack_trace.IsEmpty());
15331 CHECK_EQ(1, stack_trace->GetFrameCount());
15332 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
15336 // Test that the stack trace is captured where the bogus Error object is thrown.
15337 TEST(RethrowBogusErrorStackTrace) {
15339 v8::HandleScope scope(env->GetIsolate());
15340 const char* source =
15341 "var e = {__proto__: new Error()} \n"
15343 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
15344 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15345 CompileRun(source);
15346 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15347 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
15351 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
15352 int promise_reject_counter = 0;
15353 int promise_revoke_counter = 0;
15354 int promise_reject_msg_line_number = -1;
15355 int promise_reject_msg_column_number = -1;
15356 int promise_reject_line_number = -1;
15357 int promise_reject_column_number = -1;
15358 int promise_reject_frame_count = -1;
15360 void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
15361 if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
15362 promise_reject_counter++;
15363 CcTest::global()->Set(v8_str("rejected"), reject_message.GetPromise());
15364 CcTest::global()->Set(v8_str("value"), reject_message.GetValue());
15365 v8::Handle<v8::Message> message =
15366 v8::Exception::CreateMessage(reject_message.GetValue());
15367 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15369 promise_reject_msg_line_number = message->GetLineNumber();
15370 promise_reject_msg_column_number = message->GetStartColumn() + 1;
15372 if (!stack_trace.IsEmpty()) {
15373 promise_reject_frame_count = stack_trace->GetFrameCount();
15374 if (promise_reject_frame_count > 0) {
15375 CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
15376 promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
15377 promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn();
15379 promise_reject_line_number = -1;
15380 promise_reject_column_number = -1;
15384 promise_revoke_counter++;
15385 CcTest::global()->Set(v8_str("revoked"), reject_message.GetPromise());
15386 CHECK(reject_message.GetValue().IsEmpty());
15391 v8::Handle<v8::Promise> GetPromise(const char* name) {
15392 return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
15396 v8::Handle<v8::Value> RejectValue() {
15397 return CcTest::global()->Get(v8_str("value"));
15401 void ResetPromiseStates() {
15402 promise_reject_counter = 0;
15403 promise_revoke_counter = 0;
15404 promise_reject_msg_line_number = -1;
15405 promise_reject_msg_column_number = -1;
15406 promise_reject_line_number = -1;
15407 promise_reject_column_number = -1;
15408 promise_reject_frame_count = -1;
15409 CcTest::global()->Set(v8_str("rejected"), v8_str(""));
15410 CcTest::global()->Set(v8_str("value"), v8_str(""));
15411 CcTest::global()->Set(v8_str("revoked"), v8_str(""));
15415 TEST(PromiseRejectCallback) {
15417 v8::Isolate* isolate = env->GetIsolate();
15418 v8::HandleScope scope(isolate);
15420 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
15422 ResetPromiseStates();
15424 // Create promise p0.
15427 "var p0 = new Promise( \n"
15428 " function(res, rej) { \n"
15429 " reject = rej; \n"
15432 CHECK(!GetPromise("p0")->HasHandler());
15433 CHECK_EQ(0, promise_reject_counter);
15434 CHECK_EQ(0, promise_revoke_counter);
15436 // Add resolve handler (and default reject handler) to p0.
15437 CompileRun("var p1 = p0.then(function(){});");
15438 CHECK(GetPromise("p0")->HasHandler());
15439 CHECK(!GetPromise("p1")->HasHandler());
15440 CHECK_EQ(0, promise_reject_counter);
15441 CHECK_EQ(0, promise_revoke_counter);
15444 CompileRun("reject('ppp');");
15445 CHECK(GetPromise("p0")->HasHandler());
15446 CHECK(!GetPromise("p1")->HasHandler());
15447 CHECK_EQ(1, promise_reject_counter);
15448 CHECK_EQ(0, promise_revoke_counter);
15449 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
15450 CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
15451 CHECK(RejectValue()->Equals(v8_str("ppp")));
15453 // Reject p0 again. Callback is not triggered again.
15454 CompileRun("reject();");
15455 CHECK(GetPromise("p0")->HasHandler());
15456 CHECK(!GetPromise("p1")->HasHandler());
15457 CHECK_EQ(1, promise_reject_counter);
15458 CHECK_EQ(0, promise_revoke_counter);
15460 // Add resolve handler to p1.
15461 CompileRun("var p2 = p1.then(function(){});");
15462 CHECK(GetPromise("p0")->HasHandler());
15463 CHECK(GetPromise("p1")->HasHandler());
15464 CHECK(!GetPromise("p2")->HasHandler());
15465 CHECK_EQ(2, promise_reject_counter);
15466 CHECK_EQ(1, promise_revoke_counter);
15467 CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
15468 CHECK(RejectValue()->Equals(v8_str("ppp")));
15469 CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
15471 ResetPromiseStates();
15473 // Create promise q0.
15475 "var q0 = new Promise( \n"
15476 " function(res, rej) { \n"
15477 " reject = rej; \n"
15480 CHECK(!GetPromise("q0")->HasHandler());
15481 CHECK_EQ(0, promise_reject_counter);
15482 CHECK_EQ(0, promise_revoke_counter);
15484 // Add reject handler to q0.
15485 CompileRun("var q1 = q0.catch(function() {});");
15486 CHECK(GetPromise("q0")->HasHandler());
15487 CHECK(!GetPromise("q1")->HasHandler());
15488 CHECK_EQ(0, promise_reject_counter);
15489 CHECK_EQ(0, promise_revoke_counter);
15492 CompileRun("reject('qq')");
15493 CHECK(GetPromise("q0")->HasHandler());
15494 CHECK(!GetPromise("q1")->HasHandler());
15495 CHECK_EQ(0, promise_reject_counter);
15496 CHECK_EQ(0, promise_revoke_counter);
15498 // Add a new reject handler, which rejects by returning Promise.reject().
15499 // The returned promise q_ triggers a reject callback at first, only to
15500 // revoke it when returning it causes q2 to be rejected.
15503 "var q2 = q0.catch( \n"
15505 " q_ = Promise.reject('qqq'); \n"
15509 CHECK(GetPromise("q0")->HasHandler());
15510 CHECK(!GetPromise("q1")->HasHandler());
15511 CHECK(!GetPromise("q2")->HasHandler());
15512 CHECK(GetPromise("q_")->HasHandler());
15513 CHECK_EQ(2, promise_reject_counter);
15514 CHECK_EQ(1, promise_revoke_counter);
15515 CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
15516 CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
15517 CHECK(RejectValue()->Equals(v8_str("qqq")));
15519 // Add a reject handler to the resolved q1, which rejects by throwing.
15521 "var q3 = q1.then( \n"
15523 " throw 'qqqq'; \n"
15526 CHECK(GetPromise("q0")->HasHandler());
15527 CHECK(GetPromise("q1")->HasHandler());
15528 CHECK(!GetPromise("q2")->HasHandler());
15529 CHECK(!GetPromise("q3")->HasHandler());
15530 CHECK_EQ(3, promise_reject_counter);
15531 CHECK_EQ(1, promise_revoke_counter);
15532 CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
15533 CHECK(RejectValue()->Equals(v8_str("qqqq")));
15535 ResetPromiseStates();
15537 // Create promise r0, which has three handlers, two of which handle rejects.
15539 "var r0 = new Promise( \n"
15540 " function(res, rej) { \n"
15541 " reject = rej; \n"
15544 "var r1 = r0.catch(function() {}); \n"
15545 "var r2 = r0.then(function() {}); \n"
15546 "var r3 = r0.then(function() {}, \n"
15547 " function() {}); \n");
15548 CHECK(GetPromise("r0")->HasHandler());
15549 CHECK(!GetPromise("r1")->HasHandler());
15550 CHECK(!GetPromise("r2")->HasHandler());
15551 CHECK(!GetPromise("r3")->HasHandler());
15552 CHECK_EQ(0, promise_reject_counter);
15553 CHECK_EQ(0, promise_revoke_counter);
15556 CompileRun("reject('rrr')");
15557 CHECK(GetPromise("r0")->HasHandler());
15558 CHECK(!GetPromise("r1")->HasHandler());
15559 CHECK(!GetPromise("r2")->HasHandler());
15560 CHECK(!GetPromise("r3")->HasHandler());
15561 CHECK_EQ(1, promise_reject_counter);
15562 CHECK_EQ(0, promise_revoke_counter);
15563 CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
15564 CHECK(RejectValue()->Equals(v8_str("rrr")));
15566 // Add reject handler to r2.
15567 CompileRun("var r4 = r2.catch(function() {});");
15568 CHECK(GetPromise("r0")->HasHandler());
15569 CHECK(!GetPromise("r1")->HasHandler());
15570 CHECK(GetPromise("r2")->HasHandler());
15571 CHECK(!GetPromise("r3")->HasHandler());
15572 CHECK(!GetPromise("r4")->HasHandler());
15573 CHECK_EQ(1, promise_reject_counter);
15574 CHECK_EQ(1, promise_revoke_counter);
15575 CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
15576 CHECK(RejectValue()->Equals(v8_str("rrr")));
15578 // Add reject handlers to r4.
15579 CompileRun("var r5 = r4.then(function() {}, function() {});");
15580 CHECK(GetPromise("r0")->HasHandler());
15581 CHECK(!GetPromise("r1")->HasHandler());
15582 CHECK(GetPromise("r2")->HasHandler());
15583 CHECK(!GetPromise("r3")->HasHandler());
15584 CHECK(GetPromise("r4")->HasHandler());
15585 CHECK(!GetPromise("r5")->HasHandler());
15586 CHECK_EQ(1, promise_reject_counter);
15587 CHECK_EQ(1, promise_revoke_counter);
15589 ResetPromiseStates();
15591 // Create promise s0, which has three handlers, none of which handle rejects.
15593 "var s0 = new Promise( \n"
15594 " function(res, rej) { \n"
15595 " reject = rej; \n"
15598 "var s1 = s0.then(function() {}); \n"
15599 "var s2 = s0.then(function() {}); \n"
15600 "var s3 = s0.then(function() {}); \n");
15601 CHECK(GetPromise("s0")->HasHandler());
15602 CHECK(!GetPromise("s1")->HasHandler());
15603 CHECK(!GetPromise("s2")->HasHandler());
15604 CHECK(!GetPromise("s3")->HasHandler());
15605 CHECK_EQ(0, promise_reject_counter);
15606 CHECK_EQ(0, promise_revoke_counter);
15609 CompileRun("reject('sss')");
15610 CHECK(GetPromise("s0")->HasHandler());
15611 CHECK(!GetPromise("s1")->HasHandler());
15612 CHECK(!GetPromise("s2")->HasHandler());
15613 CHECK(!GetPromise("s3")->HasHandler());
15614 CHECK_EQ(3, promise_reject_counter);
15615 CHECK_EQ(0, promise_revoke_counter);
15616 CHECK(RejectValue()->Equals(v8_str("sss")));
15618 // Test stack frames.
15619 V8::SetCaptureStackTraceForUncaughtExceptions(true);
15621 ResetPromiseStates();
15623 // Create promise t0, which is rejected in the constructor with an error.
15624 CompileRunWithOrigin(
15625 "var t0 = new Promise( \n"
15626 " function(res, rej) { \n"
15627 " reference_error; \n"
15631 CHECK(!GetPromise("t0")->HasHandler());
15632 CHECK_EQ(1, promise_reject_counter);
15633 CHECK_EQ(0, promise_revoke_counter);
15634 CHECK_EQ(2, promise_reject_frame_count);
15635 CHECK_EQ(3, promise_reject_line_number);
15636 CHECK_EQ(5, promise_reject_column_number);
15637 CHECK_EQ(3, promise_reject_msg_line_number);
15638 CHECK_EQ(5, promise_reject_msg_column_number);
15640 ResetPromiseStates();
15642 // Create promise u0 and chain u1 to it, which is rejected via throw.
15643 CompileRunWithOrigin(
15644 "var u0 = Promise.resolve(); \n"
15645 "var u1 = u0.then( \n"
15647 " (function() { \n"
15648 " throw new Error(); \n"
15653 CHECK(GetPromise("u0")->HasHandler());
15654 CHECK(!GetPromise("u1")->HasHandler());
15655 CHECK_EQ(1, promise_reject_counter);
15656 CHECK_EQ(0, promise_revoke_counter);
15657 CHECK_EQ(2, promise_reject_frame_count);
15658 CHECK_EQ(5, promise_reject_line_number);
15659 CHECK_EQ(23, promise_reject_column_number);
15660 CHECK_EQ(5, promise_reject_msg_line_number);
15661 CHECK_EQ(23, promise_reject_msg_column_number);
15663 // Throw in u3, which handles u1's rejection.
15664 CompileRunWithOrigin(
15665 "function f() { \n"
15666 " return (function() { \n"
15667 " return new Error(); \n"
15670 "var u2 = Promise.reject(f()); \n"
15671 "var u3 = u1.catch( \n"
15677 CHECK(GetPromise("u0")->HasHandler());
15678 CHECK(GetPromise("u1")->HasHandler());
15679 CHECK(GetPromise("u2")->HasHandler());
15680 CHECK(!GetPromise("u3")->HasHandler());
15681 CHECK_EQ(3, promise_reject_counter);
15682 CHECK_EQ(2, promise_revoke_counter);
15683 CHECK_EQ(3, promise_reject_frame_count);
15684 CHECK_EQ(3, promise_reject_line_number);
15685 CHECK_EQ(12, promise_reject_column_number);
15686 CHECK_EQ(3, promise_reject_msg_line_number);
15687 CHECK_EQ(12, promise_reject_msg_column_number);
15689 ResetPromiseStates();
15691 // Create promise rejected promise v0, which is incorrectly handled by v1
15692 // via chaining cycle.
15693 CompileRunWithOrigin(
15694 "var v0 = Promise.reject(); \n"
15695 "var v1 = v0.catch( \n"
15701 CHECK(GetPromise("v0")->HasHandler());
15702 CHECK(!GetPromise("v1")->HasHandler());
15703 CHECK_EQ(2, promise_reject_counter);
15704 CHECK_EQ(1, promise_revoke_counter);
15705 CHECK_EQ(0, promise_reject_frame_count);
15706 CHECK_EQ(-1, promise_reject_line_number);
15707 CHECK_EQ(-1, promise_reject_column_number);
15709 ResetPromiseStates();
15711 // Create promise t1, which rejects by throwing syntax error from eval.
15712 CompileRunWithOrigin(
15713 "var t1 = new Promise( \n"
15714 " function(res, rej) { \n"
15715 " var content = '\\n\\\n"
15717 " eval(content); \n"
15721 CHECK(!GetPromise("t1")->HasHandler());
15722 CHECK_EQ(1, promise_reject_counter);
15723 CHECK_EQ(0, promise_revoke_counter);
15724 CHECK_EQ(2, promise_reject_frame_count);
15725 CHECK_EQ(5, promise_reject_line_number);
15726 CHECK_EQ(10, promise_reject_column_number);
15727 CHECK_EQ(2, promise_reject_msg_line_number);
15728 CHECK_EQ(7, promise_reject_msg_column_number);
15732 void AnalyzeStackOfEvalWithSourceURL(
15733 const v8::FunctionCallbackInfo<v8::Value>& args) {
15734 v8::HandleScope scope(args.GetIsolate());
15735 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15736 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15737 CHECK_EQ(5, stackTrace->GetFrameCount());
15738 v8::Handle<v8::String> url = v8_str("eval_url");
15739 for (int i = 0; i < 3; i++) {
15740 v8::Handle<v8::String> name =
15741 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15742 CHECK(!name.IsEmpty());
15743 CHECK(url->Equals(name));
15748 TEST(SourceURLInStackTrace) {
15749 v8::Isolate* isolate = CcTest::isolate();
15750 v8::HandleScope scope(isolate);
15751 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15752 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
15753 v8::FunctionTemplate::New(isolate,
15754 AnalyzeStackOfEvalWithSourceURL));
15755 LocalContext context(0, templ);
15757 const char *source =
15758 "function outer() {\n"
15759 "function bar() {\n"
15760 " AnalyzeStackOfEvalWithSourceURL();\n"
15762 "function foo() {\n"
15768 "eval('(' + outer +')()%s');";
15770 i::ScopedVector<char> code(1024);
15771 i::SNPrintF(code, source, "//# sourceURL=eval_url");
15772 CHECK(CompileRun(code.start())->IsUndefined());
15773 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
15774 CHECK(CompileRun(code.start())->IsUndefined());
15778 static int scriptIdInStack[2];
15780 void AnalyzeScriptIdInStack(
15781 const v8::FunctionCallbackInfo<v8::Value>& args) {
15782 v8::HandleScope scope(args.GetIsolate());
15783 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15784 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
15785 CHECK_EQ(2, stackTrace->GetFrameCount());
15786 for (int i = 0; i < 2; i++) {
15787 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
15792 TEST(ScriptIdInStackTrace) {
15793 v8::Isolate* isolate = CcTest::isolate();
15794 v8::HandleScope scope(isolate);
15795 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15796 templ->Set(v8_str("AnalyzeScriptIdInStack"),
15797 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
15798 LocalContext context(0, templ);
15800 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
15802 "function foo() {\n"
15803 " AnalyzeScriptIdInStack();"
15806 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
15808 for (int i = 0; i < 2; i++) {
15809 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
15810 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
15815 void AnalyzeStackOfInlineScriptWithSourceURL(
15816 const v8::FunctionCallbackInfo<v8::Value>& args) {
15817 v8::HandleScope scope(args.GetIsolate());
15818 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15819 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15820 CHECK_EQ(4, stackTrace->GetFrameCount());
15821 v8::Handle<v8::String> url = v8_str("url");
15822 for (int i = 0; i < 3; i++) {
15823 v8::Handle<v8::String> name =
15824 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15825 CHECK(!name.IsEmpty());
15826 CHECK(url->Equals(name));
15831 TEST(InlineScriptWithSourceURLInStackTrace) {
15832 v8::Isolate* isolate = CcTest::isolate();
15833 v8::HandleScope scope(isolate);
15834 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15835 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
15836 v8::FunctionTemplate::New(
15837 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
15838 LocalContext context(0, templ);
15840 const char *source =
15841 "function outer() {\n"
15842 "function bar() {\n"
15843 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
15845 "function foo() {\n"
15853 i::ScopedVector<char> code(1024);
15854 i::SNPrintF(code, source, "//# sourceURL=source_url");
15855 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15856 i::SNPrintF(code, source, "//@ sourceURL=source_url");
15857 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15861 void AnalyzeStackOfDynamicScriptWithSourceURL(
15862 const v8::FunctionCallbackInfo<v8::Value>& args) {
15863 v8::HandleScope scope(args.GetIsolate());
15864 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15865 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15866 CHECK_EQ(4, stackTrace->GetFrameCount());
15867 v8::Handle<v8::String> url = v8_str("source_url");
15868 for (int i = 0; i < 3; i++) {
15869 v8::Handle<v8::String> name =
15870 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15871 CHECK(!name.IsEmpty());
15872 CHECK(url->Equals(name));
15877 TEST(DynamicWithSourceURLInStackTrace) {
15878 v8::Isolate* isolate = CcTest::isolate();
15879 v8::HandleScope scope(isolate);
15880 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15881 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
15882 v8::FunctionTemplate::New(
15883 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
15884 LocalContext context(0, templ);
15886 const char *source =
15887 "function outer() {\n"
15888 "function bar() {\n"
15889 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
15891 "function foo() {\n"
15899 i::ScopedVector<char> code(1024);
15900 i::SNPrintF(code, source, "//# sourceURL=source_url");
15901 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15902 i::SNPrintF(code, source, "//@ sourceURL=source_url");
15903 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15907 TEST(DynamicWithSourceURLInStackTraceString) {
15908 LocalContext context;
15909 v8::HandleScope scope(context->GetIsolate());
15911 const char *source =
15912 "function outer() {\n"
15913 " function foo() {\n"
15920 i::ScopedVector<char> code(1024);
15921 i::SNPrintF(code, source, "//# sourceURL=source_url");
15922 v8::TryCatch try_catch;
15923 CompileRunWithOrigin(code.start(), "", 0, 0);
15924 CHECK(try_catch.HasCaught());
15925 v8::String::Utf8Value stack(try_catch.StackTrace());
15926 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
15930 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15931 LocalContext context;
15932 v8::HandleScope scope(context->GetIsolate());
15934 const char *source =
15935 "function outer() {\n"
15936 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
15937 " //# sourceURL=source_url\";\n"
15938 " eval(scriptContents);\n"
15941 "//# sourceURL=outer_url";
15943 v8::TryCatch try_catch;
15944 CompileRun(source);
15945 CHECK(try_catch.HasCaught());
15947 Local<v8::Message> message = try_catch.Message();
15948 Handle<Value> sourceURL =
15949 message->GetScriptOrigin().ResourceName();
15950 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15954 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15955 LocalContext context;
15956 v8::HandleScope scope(context->GetIsolate());
15958 const char *source =
15959 "function outer() {\n"
15960 " var scriptContents = \"function boo(){ boo(); }\\\n"
15961 " //# sourceURL=source_url\";\n"
15962 " eval(scriptContents);\n"
15965 "//# sourceURL=outer_url";
15967 v8::TryCatch try_catch;
15968 CompileRun(source);
15969 CHECK(try_catch.HasCaught());
15971 Local<v8::Message> message = try_catch.Message();
15972 Handle<Value> sourceURL =
15973 message->GetScriptOrigin().ResourceName();
15974 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15978 static void CreateGarbageInOldSpace() {
15979 i::Factory* factory = CcTest::i_isolate()->factory();
15980 v8::HandleScope scope(CcTest::isolate());
15981 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
15982 for (int i = 0; i < 1000; i++) {
15983 factory->NewFixedArray(1000, i::TENURED);
15988 // Test that idle notification can be handled and eventually collects garbage.
15989 TEST(TestIdleNotification) {
15990 const intptr_t MB = 1024 * 1024;
15991 const double IdlePauseInSeconds = 1.0;
15993 v8::HandleScope scope(env->GetIsolate());
15994 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
15995 CreateGarbageInOldSpace();
15996 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
15997 CHECK_GT(size_with_garbage, initial_size + MB);
15998 bool finished = false;
15999 for (int i = 0; i < 200 && !finished; i++) {
16000 finished = env->GetIsolate()->IdleNotificationDeadline(
16001 (v8::base::TimeTicks::HighResolutionNow().ToInternalValue() /
16002 static_cast<double>(v8::base::Time::kMicrosecondsPerSecond)) +
16003 IdlePauseInSeconds);
16005 intptr_t final_size = CcTest::heap()->SizeOfObjects();
16007 CHECK_LT(final_size, initial_size + 1);
16011 TEST(Regress2333) {
16013 for (int i = 0; i < 3; i++) {
16014 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
16018 static uint32_t* stack_limit;
16020 static void GetStackLimitCallback(
16021 const v8::FunctionCallbackInfo<v8::Value>& args) {
16022 stack_limit = reinterpret_cast<uint32_t*>(
16023 CcTest::i_isolate()->stack_guard()->real_climit());
16027 // Uses the address of a local variable to determine the stack top now.
16028 // Given a size, returns an address that is that far from the current
16030 static uint32_t* ComputeStackLimit(uint32_t size) {
16031 uint32_t* answer = &size - (size / sizeof(size));
16032 // If the size is very large and the stack is very near the bottom of
16033 // memory then the calculation above may wrap around and give an address
16034 // that is above the (downwards-growing) stack. In that case we return
16035 // a very low address.
16036 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
16041 // We need at least 165kB for an x64 debug build with clang and ASAN.
16042 static const int stack_breathing_room = 256 * i::KB;
16045 TEST(SetStackLimit) {
16046 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
16048 // Set stack limit.
16049 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
16051 // Execute a script.
16053 v8::HandleScope scope(env->GetIsolate());
16054 Local<v8::FunctionTemplate> fun_templ =
16055 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
16056 Local<Function> fun = fun_templ->GetFunction();
16057 env->Global()->Set(v8_str("get_stack_limit"), fun);
16058 CompileRun("get_stack_limit();");
16060 CHECK(stack_limit == set_limit);
16064 TEST(SetStackLimitInThread) {
16065 uint32_t* set_limit;
16067 v8::Locker locker(CcTest::isolate());
16068 set_limit = ComputeStackLimit(stack_breathing_room);
16070 // Set stack limit.
16071 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
16073 // Execute a script.
16074 v8::HandleScope scope(CcTest::isolate());
16076 Local<v8::FunctionTemplate> fun_templ =
16077 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
16078 Local<Function> fun = fun_templ->GetFunction();
16079 env->Global()->Set(v8_str("get_stack_limit"), fun);
16080 CompileRun("get_stack_limit();");
16082 CHECK(stack_limit == set_limit);
16085 v8::Locker locker(CcTest::isolate());
16086 CHECK(stack_limit == set_limit);
16091 THREADED_TEST(GetHeapStatistics) {
16093 v8::HandleScope scope(c1->GetIsolate());
16094 v8::HeapStatistics heap_statistics;
16095 CHECK_EQ(0u, heap_statistics.total_heap_size());
16096 CHECK_EQ(0u, heap_statistics.used_heap_size());
16097 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
16098 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
16099 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
16103 class VisitorImpl : public v8::ExternalResourceVisitor {
16105 explicit VisitorImpl(TestResource** resource) {
16106 for (int i = 0; i < 4; i++) {
16107 resource_[i] = resource[i];
16108 found_resource_[i] = false;
16111 virtual ~VisitorImpl() {}
16112 virtual void VisitExternalString(v8::Handle<v8::String> string) {
16113 if (!string->IsExternal()) {
16114 CHECK(string->IsExternalOneByte());
16117 v8::String::ExternalStringResource* resource =
16118 string->GetExternalStringResource();
16120 for (int i = 0; i < 4; i++) {
16121 if (resource_[i] == resource) {
16122 CHECK(!found_resource_[i]);
16123 found_resource_[i] = true;
16127 void CheckVisitedResources() {
16128 for (int i = 0; i < 4; i++) {
16129 CHECK(found_resource_[i]);
16134 v8::String::ExternalStringResource* resource_[4];
16135 bool found_resource_[4];
16139 TEST(ExternalizeOldSpaceTwoByteCons) {
16140 v8::Isolate* isolate = CcTest::isolate();
16142 v8::HandleScope scope(isolate);
16143 v8::Local<v8::String> cons =
16144 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
16145 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
16146 CcTest::heap()->CollectAllAvailableGarbage();
16147 CHECK(CcTest::heap()->old_pointer_space()->Contains(
16148 *v8::Utils::OpenHandle(*cons)));
16150 TestResource* resource = new TestResource(
16151 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
16152 cons->MakeExternal(resource);
16154 CHECK(cons->IsExternal());
16155 CHECK_EQ(resource, cons->GetExternalStringResource());
16156 String::Encoding encoding;
16157 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
16158 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
16162 TEST(ExternalizeOldSpaceOneByteCons) {
16163 v8::Isolate* isolate = CcTest::isolate();
16165 v8::HandleScope scope(isolate);
16166 v8::Local<v8::String> cons =
16167 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
16168 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
16169 CcTest::heap()->CollectAllAvailableGarbage();
16170 CHECK(CcTest::heap()->old_pointer_space()->Contains(
16171 *v8::Utils::OpenHandle(*cons)));
16173 TestOneByteResource* resource =
16174 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
16175 cons->MakeExternal(resource);
16177 CHECK(cons->IsExternalOneByte());
16178 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
16179 String::Encoding encoding;
16180 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
16181 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
16185 TEST(VisitExternalStrings) {
16186 v8::Isolate* isolate = CcTest::isolate();
16188 v8::HandleScope scope(isolate);
16189 const char* string = "Some string";
16190 uint16_t* two_byte_string = AsciiToTwoByteString(string);
16191 TestResource* resource[4];
16192 resource[0] = new TestResource(two_byte_string);
16193 v8::Local<v8::String> string0 =
16194 v8::String::NewExternal(env->GetIsolate(), resource[0]);
16195 resource[1] = new TestResource(two_byte_string, NULL, false);
16196 v8::Local<v8::String> string1 =
16197 v8::String::NewExternal(env->GetIsolate(), resource[1]);
16199 // Externalized symbol.
16200 resource[2] = new TestResource(two_byte_string, NULL, false);
16201 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
16202 env->GetIsolate(), string, v8::String::kInternalizedString);
16203 CHECK(string2->MakeExternal(resource[2]));
16205 // Symbolized External.
16206 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
16207 v8::Local<v8::String> string3 =
16208 v8::String::NewExternal(env->GetIsolate(), resource[3]);
16209 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
16210 // Turn into a symbol.
16211 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
16212 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
16213 string3_i).is_null());
16214 CHECK(string3_i->IsInternalizedString());
16216 // We need to add usages for string* to avoid warnings in GCC 4.7
16217 CHECK(string0->IsExternal());
16218 CHECK(string1->IsExternal());
16219 CHECK(string2->IsExternal());
16220 CHECK(string3->IsExternal());
16222 VisitorImpl visitor(resource);
16223 v8::V8::VisitExternalResources(&visitor);
16224 visitor.CheckVisitedResources();
16228 TEST(ExternalStringCollectedAtTearDown) {
16230 v8::Isolate* isolate = v8::Isolate::New();
16231 { v8::Isolate::Scope isolate_scope(isolate);
16232 v8::HandleScope handle_scope(isolate);
16233 const char* s = "One string to test them all, one string to find them.";
16234 TestOneByteResource* inscription =
16235 new TestOneByteResource(i::StrDup(s), &destroyed);
16236 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
16237 // Ring is still alive. Orcs are roaming freely across our lands.
16238 CHECK_EQ(0, destroyed);
16242 isolate->Dispose();
16243 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
16244 CHECK_EQ(1, destroyed);
16248 TEST(ExternalInternalizedStringCollectedAtTearDown) {
16250 v8::Isolate* isolate = v8::Isolate::New();
16251 { v8::Isolate::Scope isolate_scope(isolate);
16252 LocalContext env(isolate);
16253 v8::HandleScope handle_scope(isolate);
16254 CompileRun("var ring = 'One string to test them all';");
16255 const char* s = "One string to test them all";
16256 TestOneByteResource* inscription =
16257 new TestOneByteResource(i::StrDup(s), &destroyed);
16258 v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
16259 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
16260 ring->MakeExternal(inscription);
16261 // Ring is still alive. Orcs are roaming freely across our lands.
16262 CHECK_EQ(0, destroyed);
16266 isolate->Dispose();
16267 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
16268 CHECK_EQ(1, destroyed);
16272 TEST(ExternalInternalizedStringCollectedAtGC) {
16273 // TODO(mvstanton): vector ics need weak support.
16274 if (i::FLAG_vector_ics) return;
16277 { LocalContext env;
16278 v8::HandleScope handle_scope(env->GetIsolate());
16279 CompileRun("var ring = 'One string to test them all';");
16280 const char* s = "One string to test them all";
16281 TestOneByteResource* inscription =
16282 new TestOneByteResource(i::StrDup(s), &destroyed);
16283 v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
16284 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
16285 ring->MakeExternal(inscription);
16286 // Ring is still alive. Orcs are roaming freely across our lands.
16287 CHECK_EQ(0, destroyed);
16291 // Garbage collector deals swift blows to evil.
16292 CcTest::i_isolate()->compilation_cache()->Clear();
16293 CcTest::heap()->CollectAllAvailableGarbage();
16295 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
16296 CHECK_EQ(1, destroyed);
16300 static double DoubleFromBits(uint64_t value) {
16302 i::MemCopy(&target, &value, sizeof(target));
16307 static uint64_t DoubleToBits(double value) {
16309 i::MemCopy(&target, &value, sizeof(target));
16314 static double DoubleToDateTime(double input) {
16315 double date_limit = 864e13;
16316 if (std::isnan(input) || input < -date_limit || input > date_limit) {
16317 return std::numeric_limits<double>::quiet_NaN();
16319 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
16323 // We don't have a consistent way to write 64-bit constants syntactically, so we
16324 // split them into two 32-bit constants and combine them programmatically.
16325 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
16326 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
16330 THREADED_TEST(QuietSignalingNaNs) {
16331 LocalContext context;
16332 v8::Isolate* isolate = context->GetIsolate();
16333 v8::HandleScope scope(isolate);
16334 v8::TryCatch try_catch;
16336 // Special double values.
16337 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
16338 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
16339 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
16340 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
16341 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
16342 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
16343 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
16345 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
16346 // on either side of the epoch.
16347 double date_limit = 864e13;
16349 double test_values[] = {
16371 int num_test_values = 20;
16373 for (int i = 0; i < num_test_values; i++) {
16374 double test_value = test_values[i];
16376 // Check that Number::New preserves non-NaNs and quiets SNaNs.
16377 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
16378 double stored_number = number->NumberValue();
16379 if (!std::isnan(test_value)) {
16380 CHECK_EQ(test_value, stored_number);
16382 uint64_t stored_bits = DoubleToBits(stored_number);
16383 // Check if quiet nan (bits 51..62 all set).
16384 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
16385 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
16386 // Most significant fraction bit for quiet nan is set to 0
16387 // on MIPS architecture. Allowed by IEEE-754.
16388 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
16390 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
16394 // Check that Date::New preserves non-NaNs in the date range and
16396 v8::Handle<v8::Value> date =
16397 v8::Date::New(isolate, test_value);
16398 double expected_stored_date = DoubleToDateTime(test_value);
16399 double stored_date = date->NumberValue();
16400 if (!std::isnan(expected_stored_date)) {
16401 CHECK_EQ(expected_stored_date, stored_date);
16403 uint64_t stored_bits = DoubleToBits(stored_date);
16404 // Check if quiet nan (bits 51..62 all set).
16405 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
16406 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
16407 // Most significant fraction bit for quiet nan is set to 0
16408 // on MIPS architecture. Allowed by IEEE-754.
16409 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
16411 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
16418 static void SpaghettiIncident(
16419 const v8::FunctionCallbackInfo<v8::Value>& args) {
16420 v8::HandleScope scope(args.GetIsolate());
16422 v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
16424 if (tc.HasCaught())
16429 // Test that an exception can be propagated down through a spaghetti
16430 // stack using ReThrow.
16431 THREADED_TEST(SpaghettiStackReThrow) {
16432 v8::Isolate* isolate = CcTest::isolate();
16433 v8::HandleScope scope(isolate);
16434 LocalContext context;
16435 context->Global()->Set(
16436 v8::String::NewFromUtf8(isolate, "s"),
16437 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
16438 v8::TryCatch try_catch;
16442 " toString: function () {"
16452 CHECK(try_catch.HasCaught());
16453 v8::String::Utf8Value value(try_catch.Exception());
16454 CHECK_EQ(0, strcmp(*value, "Hey!"));
16459 v8::V8::Initialize();
16460 v8::Isolate* isolate = CcTest::isolate();
16461 i::FLAG_retain_maps_for_n_gc = 0;
16462 v8::HandleScope scope(isolate);
16463 v8::Local<Context> other_context;
16466 // Create a context used to keep the code from aging in the compilation
16468 other_context = Context::New(isolate);
16470 // Context-dependent context data creates reference from the compilation
16471 // cache to the global object.
16472 const char* source_simple = "1";
16474 v8::HandleScope scope(isolate);
16475 v8::Local<Context> context = Context::New(isolate);
16478 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
16479 context->SetEmbedderData(0, obj);
16480 CompileRun(source_simple);
16483 isolate->ContextDisposedNotification();
16484 for (gc_count = 1; gc_count < 10; gc_count++) {
16485 other_context->Enter();
16486 CompileRun(source_simple);
16487 other_context->Exit();
16488 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16489 if (GetGlobalObjectsCount() == 1) break;
16491 CHECK_GE(2, gc_count);
16492 CHECK_EQ(1, GetGlobalObjectsCount());
16494 // Eval in a function creates reference from the compilation cache to the
16496 const char* source_eval = "function f(){eval('1')}; f()";
16498 v8::HandleScope scope(isolate);
16499 v8::Local<Context> context = Context::New(isolate);
16502 CompileRun(source_eval);
16505 isolate->ContextDisposedNotification();
16506 for (gc_count = 1; gc_count < 10; gc_count++) {
16507 other_context->Enter();
16508 CompileRun(source_eval);
16509 other_context->Exit();
16510 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16511 if (GetGlobalObjectsCount() == 1) break;
16513 CHECK_GE(2, gc_count);
16514 CHECK_EQ(1, GetGlobalObjectsCount());
16516 // Looking up the line number for an exception creates reference from the
16517 // compilation cache to the global object.
16518 const char* source_exception = "function f(){throw 1;} f()";
16520 v8::HandleScope scope(isolate);
16521 v8::Local<Context> context = Context::New(isolate);
16524 v8::TryCatch try_catch;
16525 CompileRun(source_exception);
16526 CHECK(try_catch.HasCaught());
16527 v8::Handle<v8::Message> message = try_catch.Message();
16528 CHECK(!message.IsEmpty());
16529 CHECK_EQ(1, message->GetLineNumber());
16532 isolate->ContextDisposedNotification();
16533 for (gc_count = 1; gc_count < 10; gc_count++) {
16534 other_context->Enter();
16535 CompileRun(source_exception);
16536 other_context->Exit();
16537 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16538 if (GetGlobalObjectsCount() == 1) break;
16540 CHECK_GE(2, gc_count);
16541 CHECK_EQ(1, GetGlobalObjectsCount());
16543 isolate->ContextDisposedNotification();
16547 THREADED_TEST(ScriptOrigin) {
16549 v8::HandleScope scope(env->GetIsolate());
16550 v8::ScriptOrigin origin = v8::ScriptOrigin(
16551 v8::String::NewFromUtf8(env->GetIsolate(), "test"),
16552 v8::Integer::New(env->GetIsolate(), 1),
16553 v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
16554 v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()),
16555 v8::String::NewFromUtf8(env->GetIsolate(), "http://sourceMapUrl"));
16556 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16557 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
16558 v8::Script::Compile(script, &origin)->Run();
16559 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16560 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16561 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16562 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16564 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
16565 CHECK_EQ(0, strcmp("test",
16566 *v8::String::Utf8Value(script_origin_f.ResourceName())));
16567 CHECK_EQ(1, script_origin_f.ResourceLineOffset()->Int32Value());
16568 CHECK(script_origin_f.ResourceIsSharedCrossOrigin()->Value());
16569 CHECK(script_origin_f.ResourceIsEmbedderDebugScript()->Value());
16570 printf("is name = %d\n", script_origin_f.SourceMapUrl()->IsUndefined());
16572 CHECK_EQ(0, strcmp("http://sourceMapUrl",
16573 *v8::String::Utf8Value(script_origin_f.SourceMapUrl())));
16575 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
16576 CHECK_EQ(0, strcmp("test",
16577 *v8::String::Utf8Value(script_origin_g.ResourceName())));
16578 CHECK_EQ(1, script_origin_g.ResourceLineOffset()->Int32Value());
16579 CHECK(script_origin_g.ResourceIsSharedCrossOrigin()->Value());
16580 CHECK(script_origin_g.ResourceIsEmbedderDebugScript()->Value());
16581 CHECK_EQ(0, strcmp("http://sourceMapUrl",
16582 *v8::String::Utf8Value(script_origin_g.SourceMapUrl())));
16586 THREADED_TEST(FunctionGetInferredName) {
16588 v8::HandleScope scope(env->GetIsolate());
16589 v8::ScriptOrigin origin =
16590 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16591 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16593 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
16594 v8::Script::Compile(script, &origin)->Run();
16595 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16596 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16598 strcmp("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())));
16602 THREADED_TEST(FunctionGetDisplayName) {
16604 v8::HandleScope scope(env->GetIsolate());
16605 const char* code = "var error = false;"
16606 "function a() { this.x = 1; };"
16607 "a.displayName = 'display_a';"
16608 "var b = (function() {"
16609 " var f = function() { this.x = 2; };"
16610 " f.displayName = 'display_b';"
16613 "var c = function() {};"
16614 "c.__defineGetter__('displayName', function() {"
16616 " throw new Error();"
16619 "d.__defineGetter__('displayName', function() {"
16621 " return 'wrong_display_name';"
16624 "e.displayName = 'wrong_display_name';"
16625 "e.__defineSetter__('displayName', function() {"
16627 " throw new Error();"
16630 "f.displayName = { 'foo': 6, toString: function() {"
16632 " return 'wrong_display_name';"
16634 "var g = function() {"
16635 " arguments.callee.displayName = 'set_in_runtime';"
16638 v8::ScriptOrigin origin =
16639 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16640 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
16642 v8::Local<v8::Value> error =
16643 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
16644 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
16645 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
16646 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
16647 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
16648 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
16649 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
16650 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
16651 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
16652 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
16653 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
16654 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16655 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16656 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16657 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16658 CHECK_EQ(false, error->BooleanValue());
16659 CHECK_EQ(0, strcmp("display_a", *v8::String::Utf8Value(a->GetDisplayName())));
16660 CHECK_EQ(0, strcmp("display_b", *v8::String::Utf8Value(b->GetDisplayName())));
16661 CHECK(c->GetDisplayName()->IsUndefined());
16662 CHECK(d->GetDisplayName()->IsUndefined());
16663 CHECK(e->GetDisplayName()->IsUndefined());
16664 CHECK(f->GetDisplayName()->IsUndefined());
16666 0, strcmp("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())));
16670 THREADED_TEST(ScriptLineNumber) {
16672 v8::HandleScope scope(env->GetIsolate());
16673 v8::ScriptOrigin origin =
16674 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16675 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16676 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
16677 v8::Script::Compile(script, &origin)->Run();
16678 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16679 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16680 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16681 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16682 CHECK_EQ(0, f->GetScriptLineNumber());
16683 CHECK_EQ(2, g->GetScriptLineNumber());
16687 THREADED_TEST(ScriptColumnNumber) {
16689 v8::Isolate* isolate = env->GetIsolate();
16690 v8::HandleScope scope(isolate);
16691 v8::ScriptOrigin origin =
16692 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16693 v8::Integer::New(isolate, 3),
16694 v8::Integer::New(isolate, 2));
16695 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16696 isolate, "function foo() {}\n\n function bar() {}");
16697 v8::Script::Compile(script, &origin)->Run();
16698 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16699 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16700 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16701 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16702 CHECK_EQ(14, foo->GetScriptColumnNumber());
16703 CHECK_EQ(17, bar->GetScriptColumnNumber());
16707 THREADED_TEST(FunctionIsBuiltin) {
16709 v8::Isolate* isolate = env->GetIsolate();
16710 v8::HandleScope scope(isolate);
16711 v8::Local<v8::Function> f;
16712 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
16713 CHECK(f->IsBuiltin());
16714 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
16715 CHECK(f->IsBuiltin());
16716 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
16717 CHECK(f->IsBuiltin());
16718 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
16719 CHECK(f->IsBuiltin());
16720 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
16721 CHECK(!f->IsBuiltin());
16725 THREADED_TEST(FunctionGetScriptId) {
16727 v8::Isolate* isolate = env->GetIsolate();
16728 v8::HandleScope scope(isolate);
16729 v8::ScriptOrigin origin =
16730 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16731 v8::Integer::New(isolate, 3),
16732 v8::Integer::New(isolate, 2));
16733 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
16734 isolate, "function foo() {}\n\n function bar() {}");
16735 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
16737 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16738 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16739 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16740 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16741 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
16742 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
16746 THREADED_TEST(FunctionGetBoundFunction) {
16748 v8::HandleScope scope(env->GetIsolate());
16749 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
16750 env->GetIsolate(), "test"));
16751 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16753 "var a = new Object();\n"
16755 "function f () { return this.x };\n"
16756 "var g = f.bind(a);\n"
16758 v8::Script::Compile(script, &origin)->Run();
16759 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16760 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16761 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16762 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16763 CHECK(g->GetBoundFunction()->IsFunction());
16764 Local<v8::Function> original_function = Local<v8::Function>::Cast(
16765 g->GetBoundFunction());
16766 CHECK(f->GetName()->Equals(original_function->GetName()));
16767 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
16768 CHECK_EQ(f->GetScriptColumnNumber(),
16769 original_function->GetScriptColumnNumber());
16773 static void GetterWhichReturns42(
16774 Local<String> name,
16775 const v8::PropertyCallbackInfo<v8::Value>& info) {
16776 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16777 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16778 info.GetReturnValue().Set(v8_num(42));
16782 static void SetterWhichSetsYOnThisTo23(
16783 Local<String> name,
16784 Local<Value> value,
16785 const v8::PropertyCallbackInfo<void>& info) {
16786 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16787 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16788 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16792 void FooGetInterceptor(Local<Name> name,
16793 const v8::PropertyCallbackInfo<v8::Value>& info) {
16794 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16795 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16796 if (!name->Equals(v8_str("foo"))) return;
16797 info.GetReturnValue().Set(v8_num(42));
16801 void FooSetInterceptor(Local<Name> name, Local<Value> value,
16802 const v8::PropertyCallbackInfo<v8::Value>& info) {
16803 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16804 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16805 if (!name->Equals(v8_str("foo"))) return;
16806 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16807 info.GetReturnValue().Set(v8_num(23));
16811 TEST(SetterOnConstructorPrototype) {
16812 v8::Isolate* isolate = CcTest::isolate();
16813 v8::HandleScope scope(isolate);
16814 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16815 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16816 SetterWhichSetsYOnThisTo23);
16817 LocalContext context;
16818 context->Global()->Set(v8_str("P"), templ->NewInstance());
16819 CompileRun("function C1() {"
16822 "C1.prototype = P;"
16826 "C2.prototype = { };"
16827 "C2.prototype.__proto__ = P;");
16829 v8::Local<v8::Script> script;
16830 script = v8_compile("new C1();");
16831 for (int i = 0; i < 10; i++) {
16832 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16833 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16834 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16837 script = v8_compile("new C2();");
16838 for (int i = 0; i < 10; i++) {
16839 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16840 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
16841 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
16846 static void NamedPropertyGetterWhichReturns42(
16847 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
16848 info.GetReturnValue().Set(v8_num(42));
16852 static void NamedPropertySetterWhichSetsYOnThisTo23(
16853 Local<Name> name, Local<Value> value,
16854 const v8::PropertyCallbackInfo<v8::Value>& info) {
16855 if (name->Equals(v8_str("x"))) {
16856 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16861 THREADED_TEST(InterceptorOnConstructorPrototype) {
16862 v8::Isolate* isolate = CcTest::isolate();
16863 v8::HandleScope scope(isolate);
16864 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16865 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
16866 NamedPropertyGetterWhichReturns42,
16867 NamedPropertySetterWhichSetsYOnThisTo23));
16868 LocalContext context;
16869 context->Global()->Set(v8_str("P"), templ->NewInstance());
16870 CompileRun("function C1() {"
16873 "C1.prototype = P;"
16877 "C2.prototype = { };"
16878 "C2.prototype.__proto__ = P;");
16880 v8::Local<v8::Script> script;
16881 script = v8_compile("new C1();");
16882 for (int i = 0; i < 10; i++) {
16883 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16884 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16885 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16888 script = v8_compile("new C2();");
16889 for (int i = 0; i < 10; i++) {
16890 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16891 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
16892 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
16898 const char* source = "function C1() {"
16901 "C1.prototype = P;";
16903 LocalContext context;
16904 v8::Isolate* isolate = context->GetIsolate();
16905 v8::HandleScope scope(isolate);
16906 v8::Local<v8::Script> script;
16908 // Use a simple object as prototype.
16909 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
16910 prototype->Set(v8_str("y"), v8_num(42));
16911 context->Global()->Set(v8_str("P"), prototype);
16913 // This compile will add the code to the compilation cache.
16914 CompileRun(source);
16916 script = v8_compile("new C1();");
16917 // Allow enough iterations for the inobject slack tracking logic
16918 // to finalize instance size and install the fast construct stub.
16919 for (int i = 0; i < 256; i++) {
16920 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16921 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16922 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16925 // Use an API object with accessors as prototype.
16926 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16927 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16928 SetterWhichSetsYOnThisTo23);
16929 context->Global()->Set(v8_str("P"), templ->NewInstance());
16931 // This compile will get the code from the compilation cache.
16932 CompileRun(source);
16934 script = v8_compile("new C1();");
16935 for (int i = 0; i < 10; i++) {
16936 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16937 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16938 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16942 v8::Isolate* gc_callbacks_isolate = NULL;
16943 int prologue_call_count = 0;
16944 int epilogue_call_count = 0;
16945 int prologue_call_count_second = 0;
16946 int epilogue_call_count_second = 0;
16947 int prologue_call_count_alloc = 0;
16948 int epilogue_call_count_alloc = 0;
16950 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16951 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16952 ++prologue_call_count;
16956 void PrologueCallback(v8::Isolate* isolate,
16958 v8::GCCallbackFlags flags) {
16959 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16960 CHECK_EQ(gc_callbacks_isolate, isolate);
16961 ++prologue_call_count;
16965 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16966 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16967 ++epilogue_call_count;
16971 void EpilogueCallback(v8::Isolate* isolate,
16973 v8::GCCallbackFlags flags) {
16974 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16975 CHECK_EQ(gc_callbacks_isolate, isolate);
16976 ++epilogue_call_count;
16980 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
16981 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16982 ++prologue_call_count_second;
16986 void PrologueCallbackSecond(v8::Isolate* isolate,
16988 v8::GCCallbackFlags flags) {
16989 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16990 CHECK_EQ(gc_callbacks_isolate, isolate);
16991 ++prologue_call_count_second;
16995 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
16996 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16997 ++epilogue_call_count_second;
17001 void EpilogueCallbackSecond(v8::Isolate* isolate,
17003 v8::GCCallbackFlags flags) {
17004 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17005 CHECK_EQ(gc_callbacks_isolate, isolate);
17006 ++epilogue_call_count_second;
17010 void PrologueCallbackAlloc(v8::Isolate* isolate,
17012 v8::GCCallbackFlags flags) {
17013 v8::HandleScope scope(isolate);
17015 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17016 CHECK_EQ(gc_callbacks_isolate, isolate);
17017 ++prologue_call_count_alloc;
17019 // Simulate full heap to see if we will reenter this callback
17020 SimulateFullSpace(CcTest::heap()->new_space());
17022 Local<Object> obj = Object::New(isolate);
17023 CHECK(!obj.IsEmpty());
17025 CcTest::heap()->CollectAllGarbage(
17026 i::Heap::kAbortIncrementalMarkingMask);
17030 void EpilogueCallbackAlloc(v8::Isolate* isolate,
17032 v8::GCCallbackFlags flags) {
17033 v8::HandleScope scope(isolate);
17035 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17036 CHECK_EQ(gc_callbacks_isolate, isolate);
17037 ++epilogue_call_count_alloc;
17039 // Simulate full heap to see if we will reenter this callback
17040 SimulateFullSpace(CcTest::heap()->new_space());
17042 Local<Object> obj = Object::New(isolate);
17043 CHECK(!obj.IsEmpty());
17045 CcTest::heap()->CollectAllGarbage(
17046 i::Heap::kAbortIncrementalMarkingMask);
17050 TEST(GCCallbacksOld) {
17051 LocalContext context;
17053 v8::V8::AddGCPrologueCallback(PrologueCallback);
17054 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
17055 CHECK_EQ(0, prologue_call_count);
17056 CHECK_EQ(0, epilogue_call_count);
17057 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17058 CHECK_EQ(1, prologue_call_count);
17059 CHECK_EQ(1, epilogue_call_count);
17060 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
17061 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
17062 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17063 CHECK_EQ(2, prologue_call_count);
17064 CHECK_EQ(2, epilogue_call_count);
17065 CHECK_EQ(1, prologue_call_count_second);
17066 CHECK_EQ(1, epilogue_call_count_second);
17067 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
17068 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
17069 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17070 CHECK_EQ(2, prologue_call_count);
17071 CHECK_EQ(2, epilogue_call_count);
17072 CHECK_EQ(2, prologue_call_count_second);
17073 CHECK_EQ(2, epilogue_call_count_second);
17074 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
17075 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17076 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17077 CHECK_EQ(2, prologue_call_count);
17078 CHECK_EQ(2, epilogue_call_count);
17079 CHECK_EQ(2, prologue_call_count_second);
17080 CHECK_EQ(2, epilogue_call_count_second);
17084 TEST(GCCallbacks) {
17085 LocalContext context;
17086 v8::Isolate* isolate = context->GetIsolate();
17087 gc_callbacks_isolate = isolate;
17088 isolate->AddGCPrologueCallback(PrologueCallback);
17089 isolate->AddGCEpilogueCallback(EpilogueCallback);
17090 CHECK_EQ(0, prologue_call_count);
17091 CHECK_EQ(0, epilogue_call_count);
17092 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17093 CHECK_EQ(1, prologue_call_count);
17094 CHECK_EQ(1, epilogue_call_count);
17095 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
17096 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
17097 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17098 CHECK_EQ(2, prologue_call_count);
17099 CHECK_EQ(2, epilogue_call_count);
17100 CHECK_EQ(1, prologue_call_count_second);
17101 CHECK_EQ(1, epilogue_call_count_second);
17102 isolate->RemoveGCPrologueCallback(PrologueCallback);
17103 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
17104 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17105 CHECK_EQ(2, prologue_call_count);
17106 CHECK_EQ(2, epilogue_call_count);
17107 CHECK_EQ(2, prologue_call_count_second);
17108 CHECK_EQ(2, epilogue_call_count_second);
17109 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
17110 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17111 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17112 CHECK_EQ(2, prologue_call_count);
17113 CHECK_EQ(2, epilogue_call_count);
17114 CHECK_EQ(2, prologue_call_count_second);
17115 CHECK_EQ(2, epilogue_call_count_second);
17117 CHECK_EQ(0, prologue_call_count_alloc);
17118 CHECK_EQ(0, epilogue_call_count_alloc);
17119 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
17120 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
17121 CcTest::heap()->CollectAllGarbage(
17122 i::Heap::kAbortIncrementalMarkingMask);
17123 CHECK_EQ(1, prologue_call_count_alloc);
17124 CHECK_EQ(1, epilogue_call_count_alloc);
17125 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
17126 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
17130 THREADED_TEST(AddToJSFunctionResultCache) {
17131 i::FLAG_stress_compaction = false;
17132 i::FLAG_allow_natives_syntax = true;
17133 v8::HandleScope scope(CcTest::isolate());
17135 LocalContext context;
17141 " var r0 = %_GetFromCache(0, key0);"
17142 " var r1 = %_GetFromCache(0, key1);"
17143 " var r0_ = %_GetFromCache(0, key0);"
17145 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
17146 " var r1_ = %_GetFromCache(0, key1);"
17148 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
17149 " return 'PASSED';"
17151 CcTest::heap()->ClearJSFunctionResultCaches();
17152 ExpectString(code, "PASSED");
17156 THREADED_TEST(FillJSFunctionResultCache) {
17157 i::FLAG_allow_natives_syntax = true;
17158 LocalContext context;
17159 v8::HandleScope scope(context->GetIsolate());
17164 " var r = %_GetFromCache(0, k);"
17165 " for (var i = 0; i < 16; i++) {"
17166 " %_GetFromCache(0, 'a' + i);"
17168 " if (r === %_GetFromCache(0, k))"
17169 " return 'FAILED: k0CacheSize is too small';"
17170 " return 'PASSED';"
17172 CcTest::heap()->ClearJSFunctionResultCaches();
17173 ExpectString(code, "PASSED");
17177 THREADED_TEST(RoundRobinGetFromCache) {
17178 i::FLAG_allow_natives_syntax = true;
17179 LocalContext context;
17180 v8::HandleScope scope(context->GetIsolate());
17185 " for (var i = 0; i < 16; i++) keys.push(i);"
17186 " var values = [];"
17187 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17188 " for (var i = 0; i < 16; i++) {"
17189 " var v = %_GetFromCache(0, keys[i]);"
17190 " if (v.toString() !== values[i].toString())"
17191 " return 'Wrong value for ' + "
17192 " keys[i] + ': ' + v + ' vs. ' + values[i];"
17194 " return 'PASSED';"
17196 CcTest::heap()->ClearJSFunctionResultCaches();
17197 ExpectString(code, "PASSED");
17201 THREADED_TEST(ReverseGetFromCache) {
17202 i::FLAG_allow_natives_syntax = true;
17203 LocalContext context;
17204 v8::HandleScope scope(context->GetIsolate());
17209 " for (var i = 0; i < 16; i++) keys.push(i);"
17210 " var values = [];"
17211 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17212 " for (var i = 15; i >= 16; i--) {"
17213 " var v = %_GetFromCache(0, keys[i]);"
17214 " if (v !== values[i])"
17215 " return 'Wrong value for ' + "
17216 " keys[i] + ': ' + v + ' vs. ' + values[i];"
17218 " return 'PASSED';"
17220 CcTest::heap()->ClearJSFunctionResultCaches();
17221 ExpectString(code, "PASSED");
17225 THREADED_TEST(TestEviction) {
17226 i::FLAG_allow_natives_syntax = true;
17227 LocalContext context;
17228 v8::HandleScope scope(context->GetIsolate());
17232 " for (var i = 0; i < 2*16; i++) {"
17233 " %_GetFromCache(0, 'a' + i);"
17235 " return 'PASSED';"
17237 CcTest::heap()->ClearJSFunctionResultCaches();
17238 ExpectString(code, "PASSED");
17242 THREADED_TEST(TwoByteStringInOneByteCons) {
17243 // See Chromium issue 47824.
17244 LocalContext context;
17245 v8::HandleScope scope(context->GetIsolate());
17247 const char* init_code =
17248 "var str1 = 'abelspendabel';"
17249 "var str2 = str1 + str1 + str1;"
17251 Local<Value> result = CompileRun(init_code);
17253 Local<Value> indexof = CompileRun("str2.indexOf('els')");
17254 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
17256 CHECK(result->IsString());
17257 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
17258 int length = string->length();
17259 CHECK(string->IsOneByteRepresentation());
17261 i::Handle<i::String> flat_string = i::String::Flatten(string);
17263 CHECK(string->IsOneByteRepresentation());
17264 CHECK(flat_string->IsOneByteRepresentation());
17266 // Create external resource.
17267 uint16_t* uc16_buffer = new uint16_t[length + 1];
17269 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
17270 uc16_buffer[length] = 0;
17272 TestResource resource(uc16_buffer);
17274 flat_string->MakeExternal(&resource);
17276 CHECK(flat_string->IsTwoByteRepresentation());
17278 // If the cons string has been short-circuited, skip the following checks.
17279 if (!string.is_identical_to(flat_string)) {
17280 // At this point, we should have a Cons string which is flat and one-byte,
17281 // with a first half that is a two-byte string (although it only contains
17282 // one-byte characters). This is a valid sequence of steps, and it can
17283 // happen in real pages.
17284 CHECK(string->IsOneByteRepresentation());
17285 i::ConsString* cons = i::ConsString::cast(*string);
17286 CHECK_EQ(0, cons->second()->length());
17287 CHECK(cons->first()->IsTwoByteRepresentation());
17290 // Check that some string operations work.
17293 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
17294 CHECK_EQ(6, reresult->Int32Value());
17297 reresult = CompileRun("str2.match(/abe./g).length;");
17298 CHECK_EQ(6, reresult->Int32Value());
17300 reresult = CompileRun("str2.search(/bel/g);");
17301 CHECK_EQ(1, reresult->Int32Value());
17303 reresult = CompileRun("str2.search(/be./g);");
17304 CHECK_EQ(1, reresult->Int32Value());
17306 ExpectTrue("/bel/g.test(str2);");
17308 ExpectTrue("/be./g.test(str2);");
17310 reresult = CompileRun("/bel/g.exec(str2);");
17311 CHECK(!reresult->IsNull());
17313 reresult = CompileRun("/be./g.exec(str2);");
17314 CHECK(!reresult->IsNull());
17316 ExpectString("str2.substring(2, 10);", "elspenda");
17318 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
17320 ExpectString("str2.charAt(2);", "e");
17322 ExpectObject("str2.indexOf('els');", indexof);
17324 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
17326 reresult = CompileRun("str2.charCodeAt(2);");
17327 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
17331 TEST(ContainsOnlyOneByte) {
17332 v8::V8::Initialize();
17333 v8::Isolate* isolate = CcTest::isolate();
17334 v8::HandleScope scope(isolate);
17335 // Make a buffer long enough that it won't automatically be converted.
17336 const int length = 512;
17337 // Ensure word aligned assignment.
17338 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
17339 i::SmartArrayPointer<uintptr_t>
17340 aligned_contents(new uintptr_t[aligned_length]);
17341 uint16_t* string_contents =
17342 reinterpret_cast<uint16_t*>(aligned_contents.get());
17343 // Set to contain only one byte.
17344 for (int i = 0; i < length-1; i++) {
17345 string_contents[i] = 0x41;
17347 string_contents[length-1] = 0;
17349 Handle<String> string =
17350 String::NewExternal(isolate,
17351 new TestResource(string_contents, NULL, false));
17352 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17353 // Counter example.
17354 string = String::NewFromTwoByte(isolate, string_contents);
17355 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17356 // Test left right and balanced cons strings.
17357 Handle<String> base = String::NewFromUtf8(isolate, "a");
17358 Handle<String> left = base;
17359 Handle<String> right = base;
17360 for (int i = 0; i < 1000; i++) {
17361 left = String::Concat(base, left);
17362 right = String::Concat(right, base);
17364 Handle<String> balanced = String::Concat(left, base);
17365 balanced = String::Concat(balanced, right);
17366 Handle<String> cons_strings[] = {left, balanced, right};
17367 Handle<String> two_byte =
17368 String::NewExternal(isolate,
17369 new TestResource(string_contents, NULL, false));
17370 USE(two_byte); USE(cons_strings);
17371 for (size_t i = 0; i < arraysize(cons_strings); i++) {
17372 // Base assumptions.
17373 string = cons_strings[i];
17374 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17375 // Test left and right concatentation.
17376 string = String::Concat(two_byte, cons_strings[i]);
17377 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17378 string = String::Concat(cons_strings[i], two_byte);
17379 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17381 // Set bits in different positions
17382 // for strings of different lengths and alignments.
17383 for (int alignment = 0; alignment < 7; alignment++) {
17384 for (int size = 2; alignment + size < length; size *= 2) {
17385 int zero_offset = size + alignment;
17386 string_contents[zero_offset] = 0;
17387 for (int i = 0; i < size; i++) {
17388 int shift = 8 + (i % 7);
17389 string_contents[alignment + i] = 1 << shift;
17390 string = String::NewExternal(
17392 new TestResource(string_contents + alignment, NULL, false));
17393 CHECK_EQ(size, string->Length());
17394 CHECK(!string->ContainsOnlyOneByte());
17395 string_contents[alignment + i] = 0x41;
17397 string_contents[zero_offset] = 0x41;
17403 // Failed access check callback that performs a GC on each invocation.
17404 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
17405 v8::AccessType type,
17406 Local<v8::Value> data) {
17407 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17411 TEST(GCInFailedAccessCheckCallback) {
17412 // Install a failed access check callback that performs a GC on each
17413 // invocation. Then force the callback to be called from va
17415 v8::V8::Initialize();
17416 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
17418 v8::Isolate* isolate = CcTest::isolate();
17419 v8::HandleScope scope(isolate);
17421 // Create an ObjectTemplate for global objects and install access
17422 // check callbacks that will block access.
17423 v8::Handle<v8::ObjectTemplate> global_template =
17424 v8::ObjectTemplate::New(isolate);
17425 global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL,
17426 v8::Handle<v8::Value>(), false);
17428 // Create a context and set an x property on it's global object.
17429 LocalContext context0(NULL, global_template);
17430 context0->Global()->Set(v8_str("x"), v8_num(42));
17431 v8::Handle<v8::Object> global0 = context0->Global();
17433 // Create a context with a different security token so that the
17434 // failed access check callback will be called on each access.
17435 LocalContext context1(NULL, global_template);
17436 context1->Global()->Set(v8_str("other"), global0);
17438 // Get property with failed access check.
17439 ExpectUndefined("other.x");
17441 // Get element with failed access check.
17442 ExpectUndefined("other[0]");
17444 // Set property with failed access check.
17445 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
17446 CHECK(result->IsObject());
17448 // Set element with failed access check.
17449 result = CompileRun("other[0] = new Object()");
17450 CHECK(result->IsObject());
17452 // Get property attribute with failed access check.
17453 ExpectFalse("\'x\' in other");
17455 // Get property attribute for element with failed access check.
17456 ExpectFalse("0 in other");
17458 // Delete property.
17459 ExpectFalse("delete other.x");
17462 CHECK_EQ(false, global0->Delete(0));
17466 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
17468 // Define JavaScript accessor.
17469 ExpectUndefined("Object.prototype.__defineGetter__.call("
17470 " other, \'x\', function() { return 42; })");
17473 ExpectUndefined("Object.prototype.__lookupGetter__.call("
17477 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
17479 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
17480 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
17481 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
17483 // Reset the failed access check callback so it does not influence
17484 // the other tests.
17485 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
17489 TEST(IsolateNewDispose) {
17490 v8::Isolate* current_isolate = CcTest::isolate();
17491 v8::Isolate* isolate = v8::Isolate::New();
17492 CHECK(isolate != NULL);
17493 CHECK(current_isolate != isolate);
17494 CHECK(current_isolate == CcTest::isolate());
17496 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17497 last_location = last_message = NULL;
17498 isolate->Dispose();
17499 CHECK(!last_location);
17500 CHECK(!last_message);
17504 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
17505 v8::Isolate* isolate = v8::Isolate::New();
17507 v8::Isolate::Scope i_scope(isolate);
17508 v8::HandleScope scope(isolate);
17509 LocalContext context(isolate);
17510 // Run something in this isolate.
17511 ExpectTrue("true");
17512 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17513 last_location = last_message = NULL;
17514 // Still entered, should fail.
17515 isolate->Dispose();
17516 CHECK(last_location);
17517 CHECK(last_message);
17519 isolate->Dispose();
17523 TEST(RunTwoIsolatesOnSingleThread) {
17525 v8::Isolate* isolate1 = v8::Isolate::New();
17527 v8::Persistent<v8::Context> context1;
17529 v8::HandleScope scope(isolate1);
17530 context1.Reset(isolate1, Context::New(isolate1));
17534 v8::HandleScope scope(isolate1);
17535 v8::Local<v8::Context> context =
17536 v8::Local<v8::Context>::New(isolate1, context1);
17537 v8::Context::Scope context_scope(context);
17538 // Run something in new isolate.
17539 CompileRun("var foo = 'isolate 1';");
17540 ExpectString("function f() { return foo; }; f()", "isolate 1");
17544 v8::Isolate* isolate2 = v8::Isolate::New();
17545 v8::Persistent<v8::Context> context2;
17548 v8::Isolate::Scope iscope(isolate2);
17549 v8::HandleScope scope(isolate2);
17550 context2.Reset(isolate2, Context::New(isolate2));
17551 v8::Local<v8::Context> context =
17552 v8::Local<v8::Context>::New(isolate2, context2);
17553 v8::Context::Scope context_scope(context);
17555 // Run something in new isolate.
17556 CompileRun("var foo = 'isolate 2';");
17557 ExpectString("function f() { return foo; }; f()", "isolate 2");
17561 v8::HandleScope scope(isolate1);
17562 v8::Local<v8::Context> context =
17563 v8::Local<v8::Context>::New(isolate1, context1);
17564 v8::Context::Scope context_scope(context);
17565 // Now again in isolate 1
17566 ExpectString("function f() { return foo; }; f()", "isolate 1");
17571 // Run some stuff in default isolate.
17572 v8::Persistent<v8::Context> context_default;
17574 v8::Isolate* isolate = CcTest::isolate();
17575 v8::Isolate::Scope iscope(isolate);
17576 v8::HandleScope scope(isolate);
17577 context_default.Reset(isolate, Context::New(isolate));
17581 v8::HandleScope scope(CcTest::isolate());
17582 v8::Local<v8::Context> context =
17583 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17584 v8::Context::Scope context_scope(context);
17585 // Variables in other isolates should be not available, verify there
17586 // is an exception.
17587 ExpectTrue("function f() {"
17595 "var isDefaultIsolate = true;"
17602 v8::Isolate::Scope iscope(isolate2);
17603 v8::HandleScope scope(isolate2);
17604 v8::Local<v8::Context> context =
17605 v8::Local<v8::Context>::New(isolate2, context2);
17606 v8::Context::Scope context_scope(context);
17607 ExpectString("function f() { return foo; }; f()", "isolate 2");
17611 v8::HandleScope scope(v8::Isolate::GetCurrent());
17612 v8::Local<v8::Context> context =
17613 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
17614 v8::Context::Scope context_scope(context);
17615 ExpectString("function f() { return foo; }; f()", "isolate 1");
17619 v8::Isolate::Scope iscope(isolate2);
17626 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17627 last_location = last_message = NULL;
17629 isolate1->Dispose();
17630 CHECK(!last_location);
17631 CHECK(!last_message);
17633 isolate2->Dispose();
17634 CHECK(!last_location);
17635 CHECK(!last_message);
17637 // Check that default isolate still runs.
17639 v8::HandleScope scope(CcTest::isolate());
17640 v8::Local<v8::Context> context =
17641 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17642 v8::Context::Scope context_scope(context);
17643 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
17648 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
17649 v8::Isolate::Scope isolate_scope(isolate);
17650 v8::HandleScope scope(isolate);
17651 LocalContext context(isolate);
17652 i::ScopedVector<char> code(1024);
17653 i::SNPrintF(code, "function fib(n) {"
17654 " if (n <= 2) return 1;"
17655 " return fib(n-1) + fib(n-2);"
17658 Local<Value> value = CompileRun(code.start());
17659 CHECK(value->IsNumber());
17660 return static_cast<int>(value->NumberValue());
17663 class IsolateThread : public v8::base::Thread {
17665 explicit IsolateThread(int fib_limit)
17666 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
17669 v8::Isolate* isolate = v8::Isolate::New();
17670 result_ = CalcFibonacci(isolate, fib_limit_);
17671 isolate->Dispose();
17674 int result() { return result_; }
17682 TEST(MultipleIsolatesOnIndividualThreads) {
17683 IsolateThread thread1(21);
17684 IsolateThread thread2(12);
17686 // Compute some fibonacci numbers on 3 threads in 3 isolates.
17690 int result1 = CalcFibonacci(CcTest::isolate(), 21);
17691 int result2 = CalcFibonacci(CcTest::isolate(), 12);
17696 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
17697 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
17698 CHECK_EQ(result1, 10946);
17699 CHECK_EQ(result2, 144);
17700 CHECK_EQ(result1, thread1.result());
17701 CHECK_EQ(result2, thread2.result());
17705 TEST(IsolateDifferentContexts) {
17706 v8::Isolate* isolate = v8::Isolate::New();
17707 Local<v8::Context> context;
17709 v8::Isolate::Scope isolate_scope(isolate);
17710 v8::HandleScope handle_scope(isolate);
17711 context = v8::Context::New(isolate);
17712 v8::Context::Scope context_scope(context);
17713 Local<Value> v = CompileRun("2");
17714 CHECK(v->IsNumber());
17715 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
17718 v8::Isolate::Scope isolate_scope(isolate);
17719 v8::HandleScope handle_scope(isolate);
17720 context = v8::Context::New(isolate);
17721 v8::Context::Scope context_scope(context);
17722 Local<Value> v = CompileRun("22");
17723 CHECK(v->IsNumber());
17724 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
17726 isolate->Dispose();
17729 class InitDefaultIsolateThread : public v8::base::Thread {
17732 SetResourceConstraints,
17734 SetCounterFunction,
17735 SetCreateHistogramFunction,
17736 SetAddHistogramSampleFunction
17739 explicit InitDefaultIsolateThread(TestCase testCase)
17740 : Thread(Options("InitDefaultIsolateThread")),
17741 testCase_(testCase),
17745 v8::Isolate::CreateParams create_params;
17746 switch (testCase_) {
17747 case SetResourceConstraints: {
17748 create_params.constraints.set_max_semi_space_size(1);
17749 create_params.constraints.set_max_old_space_size(4);
17755 v8::Isolate* isolate = v8::Isolate::New(create_params);
17757 switch (testCase_) {
17758 case SetResourceConstraints:
17759 // Already handled in pre-Isolate-creation block.
17762 case SetFatalHandler:
17763 v8::V8::SetFatalErrorHandler(NULL);
17766 case SetCounterFunction:
17767 CcTest::isolate()->SetCounterFunction(NULL);
17770 case SetCreateHistogramFunction:
17771 CcTest::isolate()->SetCreateHistogramFunction(NULL);
17774 case SetAddHistogramSampleFunction:
17775 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
17779 isolate->Dispose();
17783 bool result() { return result_; }
17786 TestCase testCase_;
17791 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
17792 InitDefaultIsolateThread thread(testCase);
17795 CHECK_EQ(thread.result(), true);
17799 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
17800 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
17804 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
17805 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
17809 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
17810 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
17814 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
17815 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
17819 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
17820 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
17824 TEST(StringCheckMultipleContexts) {
17826 "(function() { return \"a\".charAt(0); })()";
17829 // Run the code twice in the first context to initialize the call IC.
17830 LocalContext context1;
17831 v8::HandleScope scope(context1->GetIsolate());
17832 ExpectString(code, "a");
17833 ExpectString(code, "a");
17837 // Change the String.prototype in the second context and check
17838 // that the right function gets called.
17839 LocalContext context2;
17840 v8::HandleScope scope(context2->GetIsolate());
17841 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
17842 ExpectString(code, "not a");
17847 TEST(NumberCheckMultipleContexts) {
17849 "(function() { return (42).toString(); })()";
17852 // Run the code twice in the first context to initialize the call IC.
17853 LocalContext context1;
17854 v8::HandleScope scope(context1->GetIsolate());
17855 ExpectString(code, "42");
17856 ExpectString(code, "42");
17860 // Change the Number.prototype in the second context and check
17861 // that the right function gets called.
17862 LocalContext context2;
17863 v8::HandleScope scope(context2->GetIsolate());
17864 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
17865 ExpectString(code, "not 42");
17870 TEST(BooleanCheckMultipleContexts) {
17872 "(function() { return true.toString(); })()";
17875 // Run the code twice in the first context to initialize the call IC.
17876 LocalContext context1;
17877 v8::HandleScope scope(context1->GetIsolate());
17878 ExpectString(code, "true");
17879 ExpectString(code, "true");
17883 // Change the Boolean.prototype in the second context and check
17884 // that the right function gets called.
17885 LocalContext context2;
17886 v8::HandleScope scope(context2->GetIsolate());
17887 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
17888 ExpectString(code, "");
17893 TEST(DontDeleteCellLoadIC) {
17894 const char* function_code =
17895 "function readCell() { while (true) { return cell; } }";
17898 // Run the code twice in the first context to initialize the load
17899 // IC for a don't delete cell.
17900 LocalContext context1;
17901 v8::HandleScope scope(context1->GetIsolate());
17902 CompileRun("var cell = \"first\";");
17903 ExpectBoolean("delete cell", false);
17904 CompileRun(function_code);
17905 ExpectString("readCell()", "first");
17906 ExpectString("readCell()", "first");
17910 // Use a deletable cell in the second context.
17911 LocalContext context2;
17912 v8::HandleScope scope(context2->GetIsolate());
17913 CompileRun("cell = \"second\";");
17914 CompileRun(function_code);
17915 ExpectString("readCell()", "second");
17916 ExpectBoolean("delete cell", true);
17917 ExpectString("(function() {"
17919 " return readCell();"
17921 " return e.toString();"
17924 "ReferenceError: cell is not defined");
17925 CompileRun("cell = \"new_second\";");
17926 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17927 ExpectString("readCell()", "new_second");
17928 ExpectString("readCell()", "new_second");
17933 class Visitor42 : public v8::PersistentHandleVisitor {
17935 explicit Visitor42(v8::Persistent<v8::Object>* object)
17936 : counter_(0), object_(object) { }
17938 virtual void VisitPersistentHandle(Persistent<Value>* value,
17939 uint16_t class_id) {
17940 if (class_id != 42) return;
17941 CHECK_EQ(42, value->WrapperClassId());
17942 v8::Isolate* isolate = CcTest::isolate();
17943 v8::HandleScope handle_scope(isolate);
17944 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
17945 v8::Handle<v8::Value> object =
17946 v8::Local<v8::Object>::New(isolate, *object_);
17947 CHECK(handle->IsObject());
17948 CHECK(Handle<Object>::Cast(handle)->Equals(object));
17953 v8::Persistent<v8::Object>* object_;
17957 TEST(PersistentHandleVisitor) {
17958 LocalContext context;
17959 v8::Isolate* isolate = context->GetIsolate();
17960 v8::HandleScope scope(isolate);
17961 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17962 CHECK_EQ(0, object.WrapperClassId());
17963 object.SetWrapperClassId(42);
17964 CHECK_EQ(42, object.WrapperClassId());
17966 Visitor42 visitor(&object);
17967 v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
17968 CHECK_EQ(1, visitor.counter_);
17974 TEST(WrapperClassId) {
17975 LocalContext context;
17976 v8::Isolate* isolate = context->GetIsolate();
17977 v8::HandleScope scope(isolate);
17978 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17979 CHECK_EQ(0, object.WrapperClassId());
17980 object.SetWrapperClassId(65535);
17981 CHECK_EQ(65535, object.WrapperClassId());
17986 TEST(PersistentHandleInNewSpaceVisitor) {
17987 LocalContext context;
17988 v8::Isolate* isolate = context->GetIsolate();
17989 v8::HandleScope scope(isolate);
17990 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
17991 CHECK_EQ(0, object1.WrapperClassId());
17992 object1.SetWrapperClassId(42);
17993 CHECK_EQ(42, object1.WrapperClassId());
17995 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17996 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17998 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
17999 CHECK_EQ(0, object2.WrapperClassId());
18000 object2.SetWrapperClassId(42);
18001 CHECK_EQ(42, object2.WrapperClassId());
18003 Visitor42 visitor(&object2);
18004 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
18005 CHECK_EQ(1, visitor.counter_);
18013 LocalContext context;
18014 v8::HandleScope scope(context->GetIsolate());
18016 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
18017 CHECK(re->IsRegExp());
18018 CHECK(re->GetSource()->Equals(v8_str("foo")));
18019 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18021 re = v8::RegExp::New(v8_str("bar"),
18022 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18023 v8::RegExp::kGlobal));
18024 CHECK(re->IsRegExp());
18025 CHECK(re->GetSource()->Equals(v8_str("bar")));
18026 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
18027 static_cast<int>(re->GetFlags()));
18029 re = v8::RegExp::New(v8_str("baz"),
18030 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18031 v8::RegExp::kMultiline));
18032 CHECK(re->IsRegExp());
18033 CHECK(re->GetSource()->Equals(v8_str("baz")));
18034 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18035 static_cast<int>(re->GetFlags()));
18037 re = CompileRun("/quux/").As<v8::RegExp>();
18038 CHECK(re->IsRegExp());
18039 CHECK(re->GetSource()->Equals(v8_str("quux")));
18040 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18042 re = CompileRun("/quux/gm").As<v8::RegExp>();
18043 CHECK(re->IsRegExp());
18044 CHECK(re->GetSource()->Equals(v8_str("quux")));
18045 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
18046 static_cast<int>(re->GetFlags()));
18048 // Override the RegExp constructor and check the API constructor
18050 CompileRun("RegExp = function() {}");
18052 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
18053 CHECK(re->IsRegExp());
18054 CHECK(re->GetSource()->Equals(v8_str("foobar")));
18055 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18057 re = v8::RegExp::New(v8_str("foobarbaz"),
18058 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18059 v8::RegExp::kMultiline));
18060 CHECK(re->IsRegExp());
18061 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
18062 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18063 static_cast<int>(re->GetFlags()));
18065 context->Global()->Set(v8_str("re"), re);
18066 ExpectTrue("re.test('FoobarbaZ')");
18068 // RegExps are objects on which you can set properties.
18069 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
18070 v8::Handle<v8::Value> value(CompileRun("re.property"));
18071 CHECK_EQ(32, value->Int32Value());
18073 v8::TryCatch try_catch;
18074 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
18075 CHECK(re.IsEmpty());
18076 CHECK(try_catch.HasCaught());
18077 context->Global()->Set(v8_str("ex"), try_catch.Exception());
18078 ExpectTrue("ex instanceof SyntaxError");
18082 THREADED_TEST(Equals) {
18083 LocalContext localContext;
18084 v8::HandleScope handleScope(localContext->GetIsolate());
18086 v8::Handle<v8::Object> globalProxy = localContext->Global();
18087 v8::Handle<Value> global = globalProxy->GetPrototype();
18089 CHECK(global->StrictEquals(global));
18090 CHECK(!global->StrictEquals(globalProxy));
18091 CHECK(!globalProxy->StrictEquals(global));
18092 CHECK(globalProxy->StrictEquals(globalProxy));
18094 CHECK(global->Equals(global));
18095 CHECK(!global->Equals(globalProxy));
18096 CHECK(!globalProxy->Equals(global));
18097 CHECK(globalProxy->Equals(globalProxy));
18101 static void Getter(v8::Local<v8::Name> property,
18102 const v8::PropertyCallbackInfo<v8::Value>& info) {
18103 info.GetReturnValue().Set(v8_str("42!"));
18107 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
18108 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
18109 result->Set(0, v8_str("universalAnswer"));
18110 info.GetReturnValue().Set(result);
18114 TEST(NamedEnumeratorAndForIn) {
18115 LocalContext context;
18116 v8::Isolate* isolate = context->GetIsolate();
18117 v8::HandleScope handle_scope(isolate);
18118 v8::Context::Scope context_scope(context.local());
18120 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
18121 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
18122 NULL, Enumerator));
18123 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
18124 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
18125 "var result = []; for (var k in o) result.push(k); result"));
18126 CHECK_EQ(1u, result->Length());
18127 CHECK(v8_str("universalAnswer")->Equals(result->Get(0)));
18131 TEST(DefinePropertyPostDetach) {
18132 LocalContext context;
18133 v8::HandleScope scope(context->GetIsolate());
18134 v8::Handle<v8::Object> proxy = context->Global();
18135 v8::Handle<v8::Function> define_property =
18136 CompileRun("(function() {"
18137 " Object.defineProperty("
18140 " { configurable: true, enumerable: true, value: 3 });"
18141 "})").As<Function>();
18142 context->DetachGlobal();
18143 define_property->Call(proxy, 0, NULL);
18147 static void InstallContextId(v8::Handle<Context> context, int id) {
18148 Context::Scope scope(context);
18149 CompileRun("Object.prototype").As<Object>()->
18150 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
18154 static void CheckContextId(v8::Handle<Object> object, int expected) {
18155 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
18159 THREADED_TEST(CreationContext) {
18160 v8::Isolate* isolate = CcTest::isolate();
18161 HandleScope handle_scope(isolate);
18162 Handle<Context> context1 = Context::New(isolate);
18163 InstallContextId(context1, 1);
18164 Handle<Context> context2 = Context::New(isolate);
18165 InstallContextId(context2, 2);
18166 Handle<Context> context3 = Context::New(isolate);
18167 InstallContextId(context3, 3);
18169 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
18171 Local<Object> object1;
18172 Local<Function> func1;
18174 Context::Scope scope(context1);
18175 object1 = Object::New(isolate);
18176 func1 = tmpl->GetFunction();
18179 Local<Object> object2;
18180 Local<Function> func2;
18182 Context::Scope scope(context2);
18183 object2 = Object::New(isolate);
18184 func2 = tmpl->GetFunction();
18187 Local<Object> instance1;
18188 Local<Object> instance2;
18191 Context::Scope scope(context3);
18192 instance1 = func1->NewInstance();
18193 instance2 = func2->NewInstance();
18197 Handle<Context> other_context = Context::New(isolate);
18198 Context::Scope scope(other_context);
18199 CHECK(object1->CreationContext() == context1);
18200 CheckContextId(object1, 1);
18201 CHECK(func1->CreationContext() == context1);
18202 CheckContextId(func1, 1);
18203 CHECK(instance1->CreationContext() == context1);
18204 CheckContextId(instance1, 1);
18205 CHECK(object2->CreationContext() == context2);
18206 CheckContextId(object2, 2);
18207 CHECK(func2->CreationContext() == context2);
18208 CheckContextId(func2, 2);
18209 CHECK(instance2->CreationContext() == context2);
18210 CheckContextId(instance2, 2);
18214 Context::Scope scope(context1);
18215 CHECK(object1->CreationContext() == context1);
18216 CheckContextId(object1, 1);
18217 CHECK(func1->CreationContext() == context1);
18218 CheckContextId(func1, 1);
18219 CHECK(instance1->CreationContext() == context1);
18220 CheckContextId(instance1, 1);
18221 CHECK(object2->CreationContext() == context2);
18222 CheckContextId(object2, 2);
18223 CHECK(func2->CreationContext() == context2);
18224 CheckContextId(func2, 2);
18225 CHECK(instance2->CreationContext() == context2);
18226 CheckContextId(instance2, 2);
18230 Context::Scope scope(context2);
18231 CHECK(object1->CreationContext() == context1);
18232 CheckContextId(object1, 1);
18233 CHECK(func1->CreationContext() == context1);
18234 CheckContextId(func1, 1);
18235 CHECK(instance1->CreationContext() == context1);
18236 CheckContextId(instance1, 1);
18237 CHECK(object2->CreationContext() == context2);
18238 CheckContextId(object2, 2);
18239 CHECK(func2->CreationContext() == context2);
18240 CheckContextId(func2, 2);
18241 CHECK(instance2->CreationContext() == context2);
18242 CheckContextId(instance2, 2);
18247 THREADED_TEST(CreationContextOfJsFunction) {
18248 HandleScope handle_scope(CcTest::isolate());
18249 Handle<Context> context = Context::New(CcTest::isolate());
18250 InstallContextId(context, 1);
18252 Local<Object> function;
18254 Context::Scope scope(context);
18255 function = CompileRun("function foo() {}; foo").As<Object>();
18258 Handle<Context> other_context = Context::New(CcTest::isolate());
18259 Context::Scope scope(other_context);
18260 CHECK(function->CreationContext() == context);
18261 CheckContextId(function, 1);
18265 void HasOwnPropertyIndexedPropertyGetter(
18267 const v8::PropertyCallbackInfo<v8::Value>& info) {
18268 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
18272 void HasOwnPropertyNamedPropertyGetter(
18273 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
18274 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
18278 void HasOwnPropertyIndexedPropertyQuery(
18279 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18280 if (index == 42) info.GetReturnValue().Set(1);
18284 void HasOwnPropertyNamedPropertyQuery(
18285 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18286 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
18290 void HasOwnPropertyNamedPropertyQuery2(
18291 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18292 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
18296 void HasOwnPropertyAccessorGetter(
18297 Local<String> property,
18298 const v8::PropertyCallbackInfo<v8::Value>& info) {
18299 info.GetReturnValue().Set(v8_str("yes"));
18303 TEST(HasOwnProperty) {
18305 v8::Isolate* isolate = env->GetIsolate();
18306 v8::HandleScope scope(isolate);
18307 { // Check normal properties and defined getters.
18308 Handle<Value> value = CompileRun(
18311 " this.__defineGetter__('baz', function() { return 1; });"
18313 "function Bar() { "
18315 " this.__defineGetter__('bla', function() { return 2; });"
18317 "Bar.prototype = new Foo();"
18319 CHECK(value->IsObject());
18320 Handle<Object> object = value->ToObject(isolate);
18321 CHECK(object->Has(v8_str("foo")));
18322 CHECK(!object->HasOwnProperty(v8_str("foo")));
18323 CHECK(object->HasOwnProperty(v8_str("bar")));
18324 CHECK(object->Has(v8_str("baz")));
18325 CHECK(!object->HasOwnProperty(v8_str("baz")));
18326 CHECK(object->HasOwnProperty(v8_str("bla")));
18328 { // Check named getter interceptors.
18329 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18330 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
18331 HasOwnPropertyNamedPropertyGetter));
18332 Handle<Object> instance = templ->NewInstance();
18333 CHECK(!instance->HasOwnProperty(v8_str("42")));
18334 CHECK(instance->HasOwnProperty(v8_str("foo")));
18335 CHECK(!instance->HasOwnProperty(v8_str("bar")));
18337 { // Check indexed getter interceptors.
18338 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18339 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
18340 HasOwnPropertyIndexedPropertyGetter));
18341 Handle<Object> instance = templ->NewInstance();
18342 CHECK(instance->HasOwnProperty(v8_str("42")));
18343 CHECK(!instance->HasOwnProperty(v8_str("43")));
18344 CHECK(!instance->HasOwnProperty(v8_str("foo")));
18346 { // Check named query interceptors.
18347 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18348 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
18349 0, 0, HasOwnPropertyNamedPropertyQuery));
18350 Handle<Object> instance = templ->NewInstance();
18351 CHECK(instance->HasOwnProperty(v8_str("foo")));
18352 CHECK(!instance->HasOwnProperty(v8_str("bar")));
18354 { // Check indexed query interceptors.
18355 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18356 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
18357 0, 0, HasOwnPropertyIndexedPropertyQuery));
18358 Handle<Object> instance = templ->NewInstance();
18359 CHECK(instance->HasOwnProperty(v8_str("42")));
18360 CHECK(!instance->HasOwnProperty(v8_str("41")));
18362 { // Check callbacks.
18363 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18364 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
18365 Handle<Object> instance = templ->NewInstance();
18366 CHECK(instance->HasOwnProperty(v8_str("foo")));
18367 CHECK(!instance->HasOwnProperty(v8_str("bar")));
18369 { // Check that query wins on disagreement.
18370 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18371 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
18372 HasOwnPropertyNamedPropertyGetter, 0,
18373 HasOwnPropertyNamedPropertyQuery2));
18374 Handle<Object> instance = templ->NewInstance();
18375 CHECK(!instance->HasOwnProperty(v8_str("foo")));
18376 CHECK(instance->HasOwnProperty(v8_str("bar")));
18381 TEST(IndexedInterceptorWithStringProto) {
18382 v8::Isolate* isolate = CcTest::isolate();
18383 v8::HandleScope scope(isolate);
18384 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18385 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
18386 NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
18387 LocalContext context;
18388 context->Global()->Set(v8_str("obj"), templ->NewInstance());
18389 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
18390 // These should be intercepted.
18391 CHECK(CompileRun("42 in obj")->BooleanValue());
18392 CHECK(CompileRun("'42' in obj")->BooleanValue());
18393 // These should fall through to the String prototype.
18394 CHECK(CompileRun("0 in obj")->BooleanValue());
18395 CHECK(CompileRun("'0' in obj")->BooleanValue());
18396 // And these should both fail.
18397 CHECK(!CompileRun("32 in obj")->BooleanValue());
18398 CHECK(!CompileRun("'32' in obj")->BooleanValue());
18402 void CheckCodeGenerationAllowed() {
18403 Handle<Value> result = CompileRun("eval('42')");
18404 CHECK_EQ(42, result->Int32Value());
18405 result = CompileRun("(function(e) { return e('42'); })(eval)");
18406 CHECK_EQ(42, result->Int32Value());
18407 result = CompileRun("var f = new Function('return 42'); f()");
18408 CHECK_EQ(42, result->Int32Value());
18412 void CheckCodeGenerationDisallowed() {
18413 TryCatch try_catch;
18415 Handle<Value> result = CompileRun("eval('42')");
18416 CHECK(result.IsEmpty());
18417 CHECK(try_catch.HasCaught());
18420 result = CompileRun("(function(e) { return e('42'); })(eval)");
18421 CHECK(result.IsEmpty());
18422 CHECK(try_catch.HasCaught());
18425 result = CompileRun("var f = new Function('return 42'); f()");
18426 CHECK(result.IsEmpty());
18427 CHECK(try_catch.HasCaught());
18431 bool CodeGenerationAllowed(Local<Context> context) {
18432 ApiTestFuzzer::Fuzz();
18437 bool CodeGenerationDisallowed(Local<Context> context) {
18438 ApiTestFuzzer::Fuzz();
18443 THREADED_TEST(AllowCodeGenFromStrings) {
18444 LocalContext context;
18445 v8::HandleScope scope(context->GetIsolate());
18447 // eval and the Function constructor allowed by default.
18448 CHECK(context->IsCodeGenerationFromStringsAllowed());
18449 CheckCodeGenerationAllowed();
18451 // Disallow eval and the Function constructor.
18452 context->AllowCodeGenerationFromStrings(false);
18453 CHECK(!context->IsCodeGenerationFromStringsAllowed());
18454 CheckCodeGenerationDisallowed();
18457 context->AllowCodeGenerationFromStrings(true);
18458 CheckCodeGenerationAllowed();
18460 // Disallow but setting a global callback that will allow the calls.
18461 context->AllowCodeGenerationFromStrings(false);
18462 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
18463 CHECK(!context->IsCodeGenerationFromStringsAllowed());
18464 CheckCodeGenerationAllowed();
18466 // Set a callback that disallows the code generation.
18467 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
18468 CHECK(!context->IsCodeGenerationFromStringsAllowed());
18469 CheckCodeGenerationDisallowed();
18473 TEST(SetErrorMessageForCodeGenFromStrings) {
18474 LocalContext context;
18475 v8::HandleScope scope(context->GetIsolate());
18476 TryCatch try_catch;
18478 Handle<String> message = v8_str("Message") ;
18479 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
18480 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
18481 context->AllowCodeGenerationFromStrings(false);
18482 context->SetErrorMessageForCodeGenerationFromStrings(message);
18483 Handle<Value> result = CompileRun("eval('42')");
18484 CHECK(result.IsEmpty());
18485 CHECK(try_catch.HasCaught());
18486 Handle<String> actual_message = try_catch.Message()->Get();
18487 CHECK(expected_message->Equals(actual_message));
18491 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
18495 THREADED_TEST(CallAPIFunctionOnNonObject) {
18496 LocalContext context;
18497 v8::Isolate* isolate = context->GetIsolate();
18498 v8::HandleScope scope(isolate);
18499 Handle<FunctionTemplate> templ =
18500 v8::FunctionTemplate::New(isolate, NonObjectThis);
18501 Handle<Function> function = templ->GetFunction();
18502 context->Global()->Set(v8_str("f"), function);
18503 TryCatch try_catch;
18504 CompileRun("f.call(2)");
18508 // Regression test for issue 1470.
18509 THREADED_TEST(ReadOnlyIndexedProperties) {
18510 v8::Isolate* isolate = CcTest::isolate();
18511 v8::HandleScope scope(isolate);
18512 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18514 LocalContext context;
18515 Local<v8::Object> obj = templ->NewInstance();
18516 context->Global()->Set(v8_str("obj"), obj);
18517 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18518 obj->Set(v8_str("1"), v8_str("foobar"));
18519 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("1"))));
18520 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
18521 obj->Set(v8_num(2), v8_str("foobar"));
18522 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_num(2))));
18524 // Test non-smi case.
18525 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18526 obj->Set(v8_str("2000000000"), v8_str("foobar"));
18527 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("2000000000"))));
18531 static int CountLiveMapsInMapCache(i::Context* context) {
18532 i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
18533 int length = map_cache->length();
18535 for (int i = 0; i < length; i++) {
18536 i::Object* value = map_cache->get(i);
18537 if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
18543 THREADED_TEST(Regress1516) {
18544 LocalContext context;
18545 v8::HandleScope scope(context->GetIsolate());
18547 // Object with 20 properties is not a common case, so it should be removed
18548 // from the cache after GC.
18549 { v8::HandleScope temp_scope(context->GetIsolate());
18552 "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
18553 "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
18554 "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
18555 "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
18559 int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
18560 CHECK_LE(1, elements);
18562 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
18564 CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
18568 THREADED_TEST(Regress93759) {
18569 v8::Isolate* isolate = CcTest::isolate();
18570 HandleScope scope(isolate);
18572 // Template for object with security check.
18573 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
18574 no_proto_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
18576 // Templates for objects with hidden prototypes and possibly security check.
18577 Local<FunctionTemplate> hidden_proto_template =
18578 v8::FunctionTemplate::New(isolate);
18579 hidden_proto_template->SetHiddenPrototype(true);
18581 Local<FunctionTemplate> protected_hidden_proto_template =
18582 v8::FunctionTemplate::New(isolate);
18583 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
18584 AccessAlwaysBlocked, NULL);
18585 protected_hidden_proto_template->SetHiddenPrototype(true);
18587 // Context for "foreign" objects used in test.
18588 Local<Context> context = v8::Context::New(isolate);
18591 // Plain object, no security check.
18592 Local<Object> simple_object = Object::New(isolate);
18594 // Object with explicit security check.
18595 Local<Object> protected_object = no_proto_template->NewInstance();
18597 // JSGlobalProxy object, always have security check.
18598 Local<Object> proxy_object = context->Global();
18600 // Global object, the prototype of proxy_object. No security checks.
18601 Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
18603 // Hidden prototype without security check.
18604 Local<Object> hidden_prototype =
18605 hidden_proto_template->GetFunction()->NewInstance();
18606 Local<Object> object_with_hidden =
18607 Object::New(isolate);
18608 object_with_hidden->SetPrototype(hidden_prototype);
18610 // Hidden prototype with security check on the hidden prototype.
18611 Local<Object> protected_hidden_prototype =
18612 protected_hidden_proto_template->GetFunction()->NewInstance();
18613 Local<Object> object_with_protected_hidden =
18614 Object::New(isolate);
18615 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
18619 // Template for object for second context. Values to test are put on it as
18621 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
18622 global_template->Set(v8_str("simple"), simple_object);
18623 global_template->Set(v8_str("protected"), protected_object);
18624 global_template->Set(v8_str("global"), global_object);
18625 global_template->Set(v8_str("proxy"), proxy_object);
18626 global_template->Set(v8_str("hidden"), object_with_hidden);
18627 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
18629 LocalContext context2(NULL, global_template);
18631 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
18632 CHECK(result1->Equals(simple_object->GetPrototype()));
18634 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
18635 CHECK(result2.IsEmpty());
18637 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
18638 CHECK(result3->Equals(global_object->GetPrototype()));
18640 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
18641 CHECK(result4.IsEmpty());
18643 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
18644 CHECK(result5->Equals(
18645 object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
18647 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
18648 CHECK(result6.IsEmpty());
18652 static void TestReceiver(Local<Value> expected_result,
18653 Local<Value> expected_receiver,
18654 const char* code) {
18655 Local<Value> result = CompileRun(code);
18656 CHECK(result->IsObject());
18657 CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
18658 CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
18662 THREADED_TEST(ForeignFunctionReceiver) {
18663 v8::Isolate* isolate = CcTest::isolate();
18664 HandleScope scope(isolate);
18666 // Create two contexts with different "id" properties ('i' and 'o').
18667 // Call a function both from its own context and from a the foreign
18668 // context, and see what "this" is bound to (returning both "this"
18669 // and "this.id" for comparison).
18671 Local<Context> foreign_context = v8::Context::New(isolate);
18672 foreign_context->Enter();
18673 Local<Value> foreign_function =
18674 CompileRun("function func() { return { 0: this.id, "
18676 " toString: function() { "
18683 CHECK(foreign_function->IsFunction());
18684 foreign_context->Exit();
18686 LocalContext context;
18688 Local<String> password = v8_str("Password");
18689 // Don't get hit by security checks when accessing foreign_context's
18690 // global receiver (aka. global proxy).
18691 context->SetSecurityToken(password);
18692 foreign_context->SetSecurityToken(password);
18694 Local<String> i = v8_str("i");
18695 Local<String> o = v8_str("o");
18696 Local<String> id = v8_str("id");
18698 CompileRun("function ownfunc() { return { 0: this.id, "
18700 " toString: function() { "
18707 context->Global()->Set(v8_str("func"), foreign_function);
18709 // Sanity check the contexts.
18710 CHECK(i->Equals(foreign_context->Global()->Get(id)));
18711 CHECK(o->Equals(context->Global()->Get(id)));
18713 // Checking local function's receiver.
18714 // Calling function using its call/apply methods.
18715 TestReceiver(o, context->Global(), "ownfunc.call()");
18716 TestReceiver(o, context->Global(), "ownfunc.apply()");
18717 // Making calls through built-in functions.
18718 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
18719 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
18720 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
18721 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
18722 // Calling with environment record as base.
18723 TestReceiver(o, context->Global(), "ownfunc()");
18724 // Calling with no base.
18725 TestReceiver(o, context->Global(), "(1,ownfunc)()");
18727 // Checking foreign function return value.
18728 // Calling function using its call/apply methods.
18729 TestReceiver(i, foreign_context->Global(), "func.call()");
18730 TestReceiver(i, foreign_context->Global(), "func.apply()");
18731 // Calling function using another context's call/apply methods.
18732 TestReceiver(i, foreign_context->Global(),
18733 "Function.prototype.call.call(func)");
18734 TestReceiver(i, foreign_context->Global(),
18735 "Function.prototype.call.apply(func)");
18736 TestReceiver(i, foreign_context->Global(),
18737 "Function.prototype.apply.call(func)");
18738 TestReceiver(i, foreign_context->Global(),
18739 "Function.prototype.apply.apply(func)");
18740 // Making calls through built-in functions.
18741 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
18742 // ToString(func()) is func()[0], i.e., the returned this.id.
18743 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
18744 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
18745 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
18747 // Calling with environment record as base.
18748 TestReceiver(i, foreign_context->Global(), "func()");
18749 // Calling with no base.
18750 TestReceiver(i, foreign_context->Global(), "(1,func)()");
18754 uint8_t callback_fired = 0;
18757 void CallCompletedCallback1() {
18758 v8::base::OS::Print("Firing callback 1.\n");
18759 callback_fired ^= 1; // Toggle first bit.
18763 void CallCompletedCallback2() {
18764 v8::base::OS::Print("Firing callback 2.\n");
18765 callback_fired ^= 2; // Toggle second bit.
18769 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
18770 int32_t level = args[0]->Int32Value();
18773 v8::base::OS::Print("Entering recursion level %d.\n", level);
18775 i::Vector<char> script_vector(script, sizeof(script));
18776 i::SNPrintF(script_vector, "recursion(%d)", level);
18777 CompileRun(script_vector.start());
18778 v8::base::OS::Print("Leaving recursion level %d.\n", level);
18779 CHECK_EQ(0, callback_fired);
18781 v8::base::OS::Print("Recursion ends.\n");
18782 CHECK_EQ(0, callback_fired);
18787 TEST(CallCompletedCallback) {
18789 v8::HandleScope scope(env->GetIsolate());
18790 v8::Handle<v8::FunctionTemplate> recursive_runtime =
18791 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
18792 env->Global()->Set(v8_str("recursion"),
18793 recursive_runtime->GetFunction());
18794 // Adding the same callback a second time has no effect.
18795 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18796 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18797 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
18798 v8::base::OS::Print("--- Script (1) ---\n");
18799 Local<Script> script = v8::Script::Compile(
18800 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
18802 CHECK_EQ(3, callback_fired);
18804 v8::base::OS::Print("\n--- Script (2) ---\n");
18805 callback_fired = 0;
18806 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
18808 CHECK_EQ(2, callback_fired);
18810 v8::base::OS::Print("\n--- Function ---\n");
18811 callback_fired = 0;
18812 Local<Function> recursive_function =
18813 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
18814 v8::Handle<Value> args[] = { v8_num(0) };
18815 recursive_function->Call(env->Global(), 1, args);
18816 CHECK_EQ(2, callback_fired);
18820 void CallCompletedCallbackNoException() {
18821 v8::HandleScope scope(CcTest::isolate());
18822 CompileRun("1+1;");
18826 void CallCompletedCallbackException() {
18827 v8::HandleScope scope(CcTest::isolate());
18828 CompileRun("throw 'second exception';");
18832 TEST(CallCompletedCallbackOneException) {
18834 v8::HandleScope scope(env->GetIsolate());
18835 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
18836 CompileRun("throw 'exception';");
18840 TEST(CallCompletedCallbackTwoExceptions) {
18842 v8::HandleScope scope(env->GetIsolate());
18843 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
18844 CompileRun("throw 'first exception';");
18848 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
18849 v8::HandleScope scope(info.GetIsolate());
18850 CompileRun("ext1Calls++;");
18854 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
18855 v8::HandleScope scope(info.GetIsolate());
18856 CompileRun("ext2Calls++;");
18860 void* g_passed_to_three = NULL;
18863 static void MicrotaskThree(void* data) {
18864 g_passed_to_three = data;
18868 TEST(EnqueueMicrotask) {
18870 v8::HandleScope scope(env->GetIsolate());
18872 "var ext1Calls = 0;"
18873 "var ext2Calls = 0;");
18874 CompileRun("1+1;");
18875 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18876 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18878 env->GetIsolate()->EnqueueMicrotask(
18879 Function::New(env->GetIsolate(), MicrotaskOne));
18880 CompileRun("1+1;");
18881 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18882 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18884 env->GetIsolate()->EnqueueMicrotask(
18885 Function::New(env->GetIsolate(), MicrotaskOne));
18886 env->GetIsolate()->EnqueueMicrotask(
18887 Function::New(env->GetIsolate(), MicrotaskTwo));
18888 CompileRun("1+1;");
18889 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18890 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18892 env->GetIsolate()->EnqueueMicrotask(
18893 Function::New(env->GetIsolate(), MicrotaskTwo));
18894 CompileRun("1+1;");
18895 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18896 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18898 CompileRun("1+1;");
18899 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18900 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18902 g_passed_to_three = NULL;
18903 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
18904 CompileRun("1+1;");
18905 CHECK(!g_passed_to_three);
18906 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18907 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18910 env->GetIsolate()->EnqueueMicrotask(
18911 Function::New(env->GetIsolate(), MicrotaskOne));
18912 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
18913 env->GetIsolate()->EnqueueMicrotask(
18914 Function::New(env->GetIsolate(), MicrotaskTwo));
18915 CompileRun("1+1;");
18916 CHECK_EQ(&dummy, g_passed_to_three);
18917 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
18918 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18919 g_passed_to_three = NULL;
18923 static void MicrotaskExceptionOne(
18924 const v8::FunctionCallbackInfo<Value>& info) {
18925 v8::HandleScope scope(info.GetIsolate());
18926 CompileRun("exception1Calls++;");
18927 info.GetIsolate()->ThrowException(
18928 v8::Exception::Error(v8_str("first")));
18932 static void MicrotaskExceptionTwo(
18933 const v8::FunctionCallbackInfo<Value>& info) {
18934 v8::HandleScope scope(info.GetIsolate());
18935 CompileRun("exception2Calls++;");
18936 info.GetIsolate()->ThrowException(
18937 v8::Exception::Error(v8_str("second")));
18941 TEST(RunMicrotasksIgnoresThrownExceptions) {
18943 v8::Isolate* isolate = env->GetIsolate();
18944 v8::HandleScope scope(isolate);
18946 "var exception1Calls = 0;"
18947 "var exception2Calls = 0;");
18948 isolate->EnqueueMicrotask(
18949 Function::New(isolate, MicrotaskExceptionOne));
18950 isolate->EnqueueMicrotask(
18951 Function::New(isolate, MicrotaskExceptionTwo));
18952 TryCatch try_catch;
18953 CompileRun("1+1;");
18954 CHECK(!try_catch.HasCaught());
18955 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
18956 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
18960 TEST(SetAutorunMicrotasks) {
18962 v8::HandleScope scope(env->GetIsolate());
18964 "var ext1Calls = 0;"
18965 "var ext2Calls = 0;");
18966 CompileRun("1+1;");
18967 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18968 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18970 env->GetIsolate()->EnqueueMicrotask(
18971 Function::New(env->GetIsolate(), MicrotaskOne));
18972 CompileRun("1+1;");
18973 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18974 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18976 env->GetIsolate()->SetAutorunMicrotasks(false);
18977 env->GetIsolate()->EnqueueMicrotask(
18978 Function::New(env->GetIsolate(), MicrotaskOne));
18979 env->GetIsolate()->EnqueueMicrotask(
18980 Function::New(env->GetIsolate(), MicrotaskTwo));
18981 CompileRun("1+1;");
18982 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18983 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18985 env->GetIsolate()->RunMicrotasks();
18986 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18987 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18989 env->GetIsolate()->EnqueueMicrotask(
18990 Function::New(env->GetIsolate(), MicrotaskTwo));
18991 CompileRun("1+1;");
18992 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18993 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18995 env->GetIsolate()->RunMicrotasks();
18996 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18997 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18999 env->GetIsolate()->SetAutorunMicrotasks(true);
19000 env->GetIsolate()->EnqueueMicrotask(
19001 Function::New(env->GetIsolate(), MicrotaskTwo));
19002 CompileRun("1+1;");
19003 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19004 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
19006 env->GetIsolate()->EnqueueMicrotask(
19007 Function::New(env->GetIsolate(), MicrotaskTwo));
19009 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
19010 CompileRun("1+1;");
19011 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19012 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
19015 CompileRun("1+1;");
19016 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19017 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
19021 TEST(RunMicrotasksWithoutEnteringContext) {
19022 v8::Isolate* isolate = CcTest::isolate();
19023 HandleScope handle_scope(isolate);
19024 isolate->SetAutorunMicrotasks(false);
19025 Handle<Context> context = Context::New(isolate);
19027 Context::Scope context_scope(context);
19028 CompileRun("var ext1Calls = 0;");
19029 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
19031 isolate->RunMicrotasks();
19033 Context::Scope context_scope(context);
19034 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
19036 isolate->SetAutorunMicrotasks(true);
19040 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
19041 v8::DebugEvent event = event_details.GetEvent();
19042 if (event != v8::Break) return;
19043 Handle<Object> exec_state = event_details.GetExecutionState();
19044 Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
19045 CompileRun("function f(id) { new FrameDetails(id, 0); }");
19046 Handle<Function> fun =
19047 Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
19048 fun->Call(CcTest::global(), 1, &break_id);
19052 TEST(Regress385349) {
19053 i::FLAG_allow_natives_syntax = true;
19054 v8::Isolate* isolate = CcTest::isolate();
19055 HandleScope handle_scope(isolate);
19056 isolate->SetAutorunMicrotasks(false);
19057 Handle<Context> context = Context::New(isolate);
19058 v8::Debug::SetDebugEventListener(DebugEventInObserver);
19060 Context::Scope context_scope(context);
19061 CompileRun("var obj = {};"
19062 "Object.observe(obj, function(changes) { debugger; });"
19065 isolate->RunMicrotasks();
19066 isolate->SetAutorunMicrotasks(true);
19067 v8::Debug::SetDebugEventListener(NULL);
19071 #ifdef ENABLE_DISASSEMBLER
19072 static int probes_counter = 0;
19073 static int misses_counter = 0;
19074 static int updates_counter = 0;
19077 static int* LookupCounter(const char* name) {
19078 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
19079 return &probes_counter;
19080 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
19081 return &misses_counter;
19082 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
19083 return &updates_counter;
19089 static const char* kMegamorphicTestProgram =
19090 "function ClassA() { };"
19091 "function ClassB() { };"
19092 "ClassA.prototype.foo = function() { };"
19093 "ClassB.prototype.foo = function() { };"
19094 "function fooify(obj) { obj.foo(); };"
19095 "var a = new ClassA();"
19096 "var b = new ClassB();"
19097 "for (var i = 0; i < 10000; i++) {"
19104 static void StubCacheHelper(bool primary) {
19105 #ifdef ENABLE_DISASSEMBLER
19106 i::FLAG_native_code_counters = true;
19108 i::FLAG_test_primary_stub_cache = true;
19110 i::FLAG_test_secondary_stub_cache = true;
19112 i::FLAG_crankshaft = false;
19114 env->GetIsolate()->SetCounterFunction(LookupCounter);
19115 v8::HandleScope scope(env->GetIsolate());
19116 int initial_probes = probes_counter;
19117 int initial_misses = misses_counter;
19118 int initial_updates = updates_counter;
19119 CompileRun(kMegamorphicTestProgram);
19120 int probes = probes_counter - initial_probes;
19121 int misses = misses_counter - initial_misses;
19122 int updates = updates_counter - initial_updates;
19123 CHECK_LT(updates, 10);
19124 CHECK_LT(misses, 10);
19125 // TODO(verwaest): Update this test to overflow the degree of polymorphism
19126 // before megamorphism. The number of probes will only work once we teach the
19127 // serializer to embed references to counters in the stubs, given that the
19128 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
19129 CHECK_GE(probes, 0);
19134 TEST(SecondaryStubCache) {
19135 StubCacheHelper(true);
19139 TEST(PrimaryStubCache) {
19140 StubCacheHelper(false);
19145 static int cow_arrays_created_runtime = 0;
19148 static int* LookupCounterCOWArrays(const char* name) {
19149 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
19150 return &cow_arrays_created_runtime;
19157 TEST(CheckCOWArraysCreatedRuntimeCounter) {
19159 i::FLAG_native_code_counters = true;
19161 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
19162 v8::HandleScope scope(env->GetIsolate());
19163 int initial_cow_arrays = cow_arrays_created_runtime;
19164 CompileRun("var o = [1, 2, 3];");
19165 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
19166 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
19167 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
19168 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
19169 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
19174 TEST(StaticGetters) {
19175 LocalContext context;
19176 i::Factory* factory = CcTest::i_isolate()->factory();
19177 v8::Isolate* isolate = CcTest::isolate();
19178 v8::HandleScope scope(isolate);
19179 i::Handle<i::Object> undefined_value = factory->undefined_value();
19180 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
19181 i::Handle<i::Object> null_value = factory->null_value();
19182 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
19183 i::Handle<i::Object> true_value = factory->true_value();
19184 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
19185 i::Handle<i::Object> false_value = factory->false_value();
19186 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
19190 UNINITIALIZED_TEST(IsolateEmbedderData) {
19191 CcTest::DisableAutomaticDispose();
19192 v8::Isolate* isolate = v8::Isolate::New();
19194 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
19195 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19196 CHECK(!isolate->GetData(slot));
19197 CHECK(!i_isolate->GetData(slot));
19199 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19200 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
19201 isolate->SetData(slot, data);
19203 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19204 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
19205 CHECK_EQ(data, isolate->GetData(slot));
19206 CHECK_EQ(data, i_isolate->GetData(slot));
19208 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19209 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
19210 isolate->SetData(slot, data);
19212 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19213 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
19214 CHECK_EQ(data, isolate->GetData(slot));
19215 CHECK_EQ(data, i_isolate->GetData(slot));
19218 isolate->Dispose();
19222 TEST(StringEmpty) {
19223 LocalContext context;
19224 i::Factory* factory = CcTest::i_isolate()->factory();
19225 v8::Isolate* isolate = CcTest::isolate();
19226 v8::HandleScope scope(isolate);
19227 i::Handle<i::Object> empty_string = factory->empty_string();
19228 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
19232 static int instance_checked_getter_count = 0;
19233 static void InstanceCheckedGetter(
19234 Local<String> name,
19235 const v8::PropertyCallbackInfo<v8::Value>& info) {
19236 CHECK(name->Equals(v8_str("foo")));
19237 instance_checked_getter_count++;
19238 info.GetReturnValue().Set(v8_num(11));
19242 static int instance_checked_setter_count = 0;
19243 static void InstanceCheckedSetter(Local<String> name,
19244 Local<Value> value,
19245 const v8::PropertyCallbackInfo<void>& info) {
19246 CHECK(name->Equals(v8_str("foo")));
19247 CHECK(value->Equals(v8_num(23)));
19248 instance_checked_setter_count++;
19252 static void CheckInstanceCheckedResult(int getters, int setters,
19253 bool expects_callbacks,
19254 TryCatch* try_catch) {
19255 if (expects_callbacks) {
19256 CHECK(!try_catch->HasCaught());
19257 CHECK_EQ(getters, instance_checked_getter_count);
19258 CHECK_EQ(setters, instance_checked_setter_count);
19260 CHECK(try_catch->HasCaught());
19261 CHECK_EQ(0, instance_checked_getter_count);
19262 CHECK_EQ(0, instance_checked_setter_count);
19264 try_catch->Reset();
19268 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
19269 instance_checked_getter_count = 0;
19270 instance_checked_setter_count = 0;
19271 TryCatch try_catch;
19273 // Test path through generic runtime code.
19274 CompileRun("obj.foo");
19275 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
19276 CompileRun("obj.foo = 23");
19277 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
19279 // Test path through generated LoadIC and StoredIC.
19280 CompileRun("function test_get(o) { o.foo; }"
19282 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
19283 CompileRun("test_get(obj);");
19284 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
19285 CompileRun("test_get(obj);");
19286 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
19287 CompileRun("function test_set(o) { o.foo = 23; }"
19289 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
19290 CompileRun("test_set(obj);");
19291 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
19292 CompileRun("test_set(obj);");
19293 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
19295 // Test path through optimized code.
19296 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
19298 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
19299 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
19301 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
19303 // Cleanup so that closures start out fresh in next check.
19304 CompileRun("%DeoptimizeFunction(test_get);"
19305 "%ClearFunctionTypeFeedback(test_get);"
19306 "%DeoptimizeFunction(test_set);"
19307 "%ClearFunctionTypeFeedback(test_set);");
19311 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
19312 v8::internal::FLAG_allow_natives_syntax = true;
19313 LocalContext context;
19314 v8::HandleScope scope(context->GetIsolate());
19316 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
19317 Local<ObjectTemplate> inst = templ->InstanceTemplate();
19318 inst->SetAccessor(v8_str("foo"),
19319 InstanceCheckedGetter, InstanceCheckedSetter,
19323 v8::AccessorSignature::New(context->GetIsolate(), templ));
19324 context->Global()->Set(v8_str("f"), templ->GetFunction());
19326 printf("Testing positive ...\n");
19327 CompileRun("var obj = new f();");
19328 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19329 CheckInstanceCheckedAccessors(true);
19331 printf("Testing negative ...\n");
19332 CompileRun("var obj = {};"
19333 "obj.__proto__ = new f();");
19334 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19335 CheckInstanceCheckedAccessors(false);
19339 static void EmptyInterceptorGetter(
19340 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
19343 static void EmptyInterceptorSetter(
19344 Local<String> name, Local<Value> value,
19345 const v8::PropertyCallbackInfo<v8::Value>& info) {}
19348 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
19349 v8::internal::FLAG_allow_natives_syntax = true;
19350 LocalContext context;
19351 v8::HandleScope scope(context->GetIsolate());
19353 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
19354 Local<ObjectTemplate> inst = templ->InstanceTemplate();
19355 templ->InstanceTemplate()->SetNamedPropertyHandler(EmptyInterceptorGetter,
19356 EmptyInterceptorSetter);
19357 inst->SetAccessor(v8_str("foo"),
19358 InstanceCheckedGetter, InstanceCheckedSetter,
19362 v8::AccessorSignature::New(context->GetIsolate(), templ));
19363 context->Global()->Set(v8_str("f"), templ->GetFunction());
19365 printf("Testing positive ...\n");
19366 CompileRun("var obj = new f();");
19367 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19368 CheckInstanceCheckedAccessors(true);
19370 printf("Testing negative ...\n");
19371 CompileRun("var obj = {};"
19372 "obj.__proto__ = new f();");
19373 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19374 CheckInstanceCheckedAccessors(false);
19378 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
19379 v8::internal::FLAG_allow_natives_syntax = true;
19380 LocalContext context;
19381 v8::HandleScope scope(context->GetIsolate());
19383 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
19384 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
19385 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
19386 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
19388 v8::AccessorSignature::New(context->GetIsolate(), templ));
19389 context->Global()->Set(v8_str("f"), templ->GetFunction());
19391 printf("Testing positive ...\n");
19392 CompileRun("var obj = new f();");
19393 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19394 CheckInstanceCheckedAccessors(true);
19396 printf("Testing negative ...\n");
19397 CompileRun("var obj = {};"
19398 "obj.__proto__ = new f();");
19399 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19400 CheckInstanceCheckedAccessors(false);
19402 printf("Testing positive with modified prototype chain ...\n");
19403 CompileRun("var obj = new f();"
19405 "pro.__proto__ = obj.__proto__;"
19406 "obj.__proto__ = pro;");
19407 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19408 CheckInstanceCheckedAccessors(true);
19412 TEST(TryFinallyMessage) {
19413 LocalContext context;
19414 v8::HandleScope scope(context->GetIsolate());
19416 // Test that the original error message is not lost if there is a
19417 // recursive call into Javascript is done in the finally block, e.g. to
19418 // initialize an IC. (crbug.com/129171)
19419 TryCatch try_catch;
19420 const char* trigger_ic =
19422 " throw new Error('test'); \n"
19425 " x++; \n" // Trigger an IC initialization here.
19427 CompileRun(trigger_ic);
19428 CHECK(try_catch.HasCaught());
19429 Local<Message> message = try_catch.Message();
19430 CHECK(!message.IsEmpty());
19431 CHECK_EQ(2, message->GetLineNumber());
19435 // Test that the original exception message is indeed overwritten if
19436 // a new error is thrown in the finally block.
19437 TryCatch try_catch;
19438 const char* throw_again =
19440 " throw new Error('test'); \n"
19444 " throw new Error('again'); \n" // This is the new uncaught error.
19446 CompileRun(throw_again);
19447 CHECK(try_catch.HasCaught());
19448 Local<Message> message = try_catch.Message();
19449 CHECK(!message.IsEmpty());
19450 CHECK_EQ(6, message->GetLineNumber());
19455 static void Helper137002(bool do_store,
19457 bool remove_accessor,
19458 bool interceptor) {
19459 LocalContext context;
19460 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
19462 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
19463 FooSetInterceptor));
19465 templ->SetAccessor(v8_str("foo"),
19466 GetterWhichReturns42,
19467 SetterWhichSetsYOnThisTo23);
19469 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19471 // Turn monomorphic on slow object with native accessor, then turn
19472 // polymorphic, finally optimize to create negative lookup and fail.
19473 CompileRun(do_store ?
19474 "function f(x) { x.foo = void 0; }" :
19475 "function f(x) { return x.foo; }");
19476 CompileRun("obj.y = void 0;");
19477 if (!interceptor) {
19478 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
19480 CompileRun("obj.__proto__ = null;"
19481 "f(obj); f(obj); f(obj);");
19483 CompileRun("f({});");
19485 CompileRun("obj.y = void 0;"
19486 "%OptimizeFunctionOnNextCall(f);");
19487 if (remove_accessor) {
19488 CompileRun("delete obj.foo;");
19490 CompileRun("var result = f(obj);");
19492 CompileRun("result = obj.y;");
19494 if (remove_accessor && !interceptor) {
19495 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
19497 CHECK_EQ(do_store ? 23 : 42,
19498 context->Global()->Get(v8_str("result"))->Int32Value());
19503 THREADED_TEST(Regress137002a) {
19504 i::FLAG_allow_natives_syntax = true;
19505 i::FLAG_compilation_cache = false;
19506 v8::HandleScope scope(CcTest::isolate());
19507 for (int i = 0; i < 16; i++) {
19508 Helper137002(i & 8, i & 4, i & 2, i & 1);
19513 THREADED_TEST(Regress137002b) {
19514 i::FLAG_allow_natives_syntax = true;
19515 LocalContext context;
19516 v8::Isolate* isolate = context->GetIsolate();
19517 v8::HandleScope scope(isolate);
19518 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19519 templ->SetAccessor(v8_str("foo"),
19520 GetterWhichReturns42,
19521 SetterWhichSetsYOnThisTo23);
19522 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19524 // Turn monomorphic on slow object with native accessor, then just
19525 // delete the property and fail.
19526 CompileRun("function load(x) { return x.foo; }"
19527 "function store(x) { x.foo = void 0; }"
19528 "function keyed_load(x, key) { return x[key]; }"
19529 // Second version of function has a different source (add void 0)
19530 // so that it does not share code with the first version. This
19531 // ensures that the ICs are monomorphic.
19532 "function load2(x) { void 0; return x.foo; }"
19533 "function store2(x) { void 0; x.foo = void 0; }"
19534 "function keyed_load2(x, key) { void 0; return x[key]; }"
19537 "obj.__proto__ = null;"
19539 "subobj.y = void 0;"
19540 "subobj.__proto__ = obj;"
19541 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19543 // Make the ICs monomorphic.
19544 "load(obj); load(obj);"
19545 "load2(subobj); load2(subobj);"
19546 "store(obj); store(obj);"
19547 "store2(subobj); store2(subobj);"
19548 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
19549 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
19551 // Actually test the shiny new ICs and better not crash. This
19552 // serves as a regression test for issue 142088 as well.
19557 "keyed_load(obj, 'foo');"
19558 "keyed_load2(subobj, 'foo');"
19560 // Delete the accessor. It better not be called any more now.
19563 "subobj.y = void 0;"
19565 "var load_result = load(obj);"
19566 "var load_result2 = load2(subobj);"
19567 "var keyed_load_result = keyed_load(obj, 'foo');"
19568 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
19571 "var y_from_obj = obj.y;"
19572 "var y_from_subobj = subobj.y;");
19573 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
19574 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
19575 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
19576 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
19577 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
19578 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
19582 THREADED_TEST(Regress142088) {
19583 i::FLAG_allow_natives_syntax = true;
19584 LocalContext context;
19585 v8::Isolate* isolate = context->GetIsolate();
19586 v8::HandleScope scope(isolate);
19587 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19588 templ->SetAccessor(v8_str("foo"),
19589 GetterWhichReturns42,
19590 SetterWhichSetsYOnThisTo23);
19591 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19593 CompileRun("function load(x) { return x.foo; }"
19594 "var o = Object.create(obj);"
19595 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19596 "load(o); load(o); load(o); load(o);");
19600 THREADED_TEST(Regress3337) {
19601 LocalContext context;
19602 v8::Isolate* isolate = context->GetIsolate();
19603 v8::HandleScope scope(isolate);
19604 Local<v8::Object> o1 = Object::New(isolate);
19605 Local<v8::Object> o2 = Object::New(isolate);
19606 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
19607 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
19608 CHECK(io1->map() == io2->map());
19609 o1->SetIndexedPropertiesToExternalArrayData(
19610 NULL, v8::kExternalUint32Array, 0);
19611 o2->SetIndexedPropertiesToExternalArrayData(
19612 NULL, v8::kExternalUint32Array, 0);
19613 CHECK(io1->map() == io2->map());
19617 THREADED_TEST(Regress137496) {
19618 i::FLAG_expose_gc = true;
19619 LocalContext context;
19620 v8::HandleScope scope(context->GetIsolate());
19622 // Compile a try-finally clause where the finally block causes a GC
19623 // while there still is a message pending for external reporting.
19624 TryCatch try_catch;
19625 try_catch.SetVerbose(true);
19626 CompileRun("try { throw new Error(); } finally { gc(); }");
19627 CHECK(try_catch.HasCaught());
19631 THREADED_TEST(Regress157124) {
19632 LocalContext context;
19633 v8::Isolate* isolate = context->GetIsolate();
19634 v8::HandleScope scope(isolate);
19635 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19636 Local<Object> obj = templ->NewInstance();
19637 obj->GetIdentityHash();
19638 obj->DeleteHiddenValue(v8_str("Bug"));
19642 THREADED_TEST(Regress2535) {
19643 LocalContext context;
19644 v8::HandleScope scope(context->GetIsolate());
19645 Local<Value> set_value = CompileRun("new Set();");
19646 Local<Object> set_object(Local<Object>::Cast(set_value));
19647 CHECK_EQ(0, set_object->InternalFieldCount());
19648 Local<Value> map_value = CompileRun("new Map();");
19649 Local<Object> map_object(Local<Object>::Cast(map_value));
19650 CHECK_EQ(0, map_object->InternalFieldCount());
19654 THREADED_TEST(Regress2746) {
19655 LocalContext context;
19656 v8::Isolate* isolate = context->GetIsolate();
19657 v8::HandleScope scope(isolate);
19658 Local<Object> obj = Object::New(isolate);
19659 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
19660 obj->SetHiddenValue(key, v8::Undefined(isolate));
19661 Local<Value> value = obj->GetHiddenValue(key);
19662 CHECK(!value.IsEmpty());
19663 CHECK(value->IsUndefined());
19667 THREADED_TEST(Regress260106) {
19668 LocalContext context;
19669 v8::Isolate* isolate = context->GetIsolate();
19670 v8::HandleScope scope(isolate);
19671 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
19673 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
19674 Local<Function> function = templ->GetFunction();
19675 CHECK(!function.IsEmpty());
19676 CHECK(function->IsFunction());
19680 THREADED_TEST(JSONParseObject) {
19681 LocalContext context;
19682 HandleScope scope(context->GetIsolate());
19683 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
19684 Handle<Object> global = context->Global();
19685 global->Set(v8_str("obj"), obj);
19686 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
19690 THREADED_TEST(JSONParseNumber) {
19691 LocalContext context;
19692 HandleScope scope(context->GetIsolate());
19693 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
19694 Handle<Object> global = context->Global();
19695 global->Set(v8_str("obj"), obj);
19696 ExpectString("JSON.stringify(obj)", "42");
19700 #if V8_OS_POSIX && !V8_OS_NACL
19701 class ThreadInterruptTest {
19703 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
19704 ~ThreadInterruptTest() {}
19707 InterruptThread i_thread(this);
19711 CHECK_EQ(kExpectedValue, sem_value_);
19715 static const int kExpectedValue = 1;
19717 class InterruptThread : public v8::base::Thread {
19719 explicit InterruptThread(ThreadInterruptTest* test)
19720 : Thread(Options("InterruptThread")), test_(test) {}
19722 virtual void Run() {
19723 struct sigaction action;
19725 // Ensure that we'll enter waiting condition
19726 v8::base::OS::Sleep(100);
19728 // Setup signal handler
19729 memset(&action, 0, sizeof(action));
19730 action.sa_handler = SignalHandler;
19731 sigaction(SIGCHLD, &action, NULL);
19734 kill(getpid(), SIGCHLD);
19736 // Ensure that if wait has returned because of error
19737 v8::base::OS::Sleep(100);
19739 // Set value and signal semaphore
19740 test_->sem_value_ = 1;
19741 test_->sem_.Signal();
19744 static void SignalHandler(int signal) {
19748 ThreadInterruptTest* test_;
19751 v8::base::Semaphore sem_;
19752 volatile int sem_value_;
19756 THREADED_TEST(SemaphoreInterruption) {
19757 ThreadInterruptTest().RunTest();
19761 #endif // V8_OS_POSIX
19764 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19769 TEST(JSONStringifyAccessCheck) {
19770 v8::V8::Initialize();
19771 v8::Isolate* isolate = CcTest::isolate();
19772 v8::HandleScope scope(isolate);
19774 // Create an ObjectTemplate for global objects and install access
19775 // check callbacks that will block access.
19776 v8::Handle<v8::ObjectTemplate> global_template =
19777 v8::ObjectTemplate::New(isolate);
19778 global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
19780 // Create a context and set an x property on it's global object.
19781 LocalContext context0(NULL, global_template);
19782 v8::Handle<v8::Object> global0 = context0->Global();
19783 global0->Set(v8_str("x"), v8_num(42));
19784 ExpectString("JSON.stringify(this)", "{\"x\":42}");
19786 for (int i = 0; i < 2; i++) {
19788 // Install a toJSON function on the second run.
19789 v8::Handle<v8::FunctionTemplate> toJSON =
19790 v8::FunctionTemplate::New(isolate, UnreachableCallback);
19792 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
19794 // Create a context with a different security token so that the
19795 // failed access check callback will be called on each access.
19796 LocalContext context1(NULL, global_template);
19797 context1->Global()->Set(v8_str("other"), global0);
19799 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
19800 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
19801 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
19803 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
19804 array->Set(0, v8_str("a"));
19805 array->Set(1, v8_str("b"));
19806 context1->Global()->Set(v8_str("array"), array);
19807 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
19808 array->TurnOnAccessCheck();
19809 CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
19810 CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
19811 CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
19816 bool access_check_fail_thrown = false;
19817 bool catch_callback_called = false;
19820 // Failed access check callback that performs a GC on each invocation.
19821 void FailedAccessCheckThrows(Local<v8::Object> target,
19822 v8::AccessType type,
19823 Local<v8::Value> data) {
19824 access_check_fail_thrown = true;
19825 i::PrintF("Access check failed. Error thrown.\n");
19826 CcTest::isolate()->ThrowException(
19827 v8::Exception::Error(v8_str("cross context")));
19831 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19832 for (int i = 0; i < args.Length(); i++) {
19833 i::PrintF("%s\n", *String::Utf8Value(args[i]));
19835 catch_callback_called = true;
19839 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19840 args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
19841 args[1]->ToString(args.GetIsolate()));
19845 void CheckCorrectThrow(const char* script) {
19846 // Test that the script, when wrapped into a try-catch, triggers the catch
19847 // clause due to failed access check throwing an exception.
19848 // The subsequent try-catch should run without any exception.
19849 access_check_fail_thrown = false;
19850 catch_callback_called = false;
19851 i::ScopedVector<char> source(1024);
19852 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
19853 CompileRun(source.start());
19854 CHECK(access_check_fail_thrown);
19855 CHECK(catch_callback_called);
19857 access_check_fail_thrown = false;
19858 catch_callback_called = false;
19859 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
19860 CHECK(!access_check_fail_thrown);
19861 CHECK(!catch_callback_called);
19865 TEST(AccessCheckThrows) {
19866 i::FLAG_allow_natives_syntax = true;
19867 v8::V8::Initialize();
19868 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
19869 v8::Isolate* isolate = CcTest::isolate();
19870 v8::HandleScope scope(isolate);
19872 // Create an ObjectTemplate for global objects and install access
19873 // check callbacks that will block access.
19874 v8::Handle<v8::ObjectTemplate> global_template =
19875 v8::ObjectTemplate::New(isolate);
19876 global_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
19878 // Create a context and set an x property on it's global object.
19879 LocalContext context0(NULL, global_template);
19880 v8::Handle<v8::Object> global0 = context0->Global();
19882 // Create a context with a different security token so that the
19883 // failed access check callback will be called on each access.
19884 LocalContext context1(NULL, global_template);
19885 context1->Global()->Set(v8_str("other"), global0);
19887 v8::Handle<v8::FunctionTemplate> catcher_fun =
19888 v8::FunctionTemplate::New(isolate, CatcherCallback);
19889 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
19891 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
19892 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
19893 context1->Global()->Set(v8_str("has_own_property"),
19894 has_own_property_fun->GetFunction());
19896 { v8::TryCatch try_catch;
19897 access_check_fail_thrown = false;
19898 CompileRun("other.x;");
19899 CHECK(access_check_fail_thrown);
19900 CHECK(try_catch.HasCaught());
19903 CheckCorrectThrow("other.x");
19904 CheckCorrectThrow("other[1]");
19905 CheckCorrectThrow("JSON.stringify(other)");
19906 CheckCorrectThrow("has_own_property(other, 'x')");
19907 CheckCorrectThrow("%GetProperty(other, 'x')");
19908 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
19909 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
19910 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
19911 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
19912 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
19913 CheckCorrectThrow("%HasProperty(other, 'x')");
19914 CheckCorrectThrow("%HasElement(other, 1)");
19915 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
19916 CheckCorrectThrow("%GetPropertyNames(other)");
19917 // PROPERTY_ATTRIBUTES_NONE = 0
19918 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
19919 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
19920 "other, 'x', null, null, 1)");
19922 // Reset the failed access check callback so it does not influence
19923 // the other tests.
19924 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
19928 class RequestInterruptTestBase {
19930 RequestInterruptTestBase()
19932 isolate_(env_->GetIsolate()),
19935 should_continue_(true) {
19938 virtual ~RequestInterruptTestBase() { }
19940 virtual void StartInterruptThread() = 0;
19942 virtual void TestBody() = 0;
19945 StartInterruptThread();
19947 v8::HandleScope handle_scope(isolate_);
19951 // Verify we arrived here because interruptor was called
19952 // not due to a bug causing us to exit the loop too early.
19953 CHECK(!should_continue());
19956 void WakeUpInterruptor() {
19960 bool should_continue() const { return should_continue_; }
19962 bool ShouldContinue() {
19964 if (--warmup_ == 0) {
19965 WakeUpInterruptor();
19969 return should_continue_;
19972 static void ShouldContinueCallback(
19973 const v8::FunctionCallbackInfo<Value>& info) {
19974 RequestInterruptTestBase* test =
19975 reinterpret_cast<RequestInterruptTestBase*>(
19976 info.Data().As<v8::External>()->Value());
19977 info.GetReturnValue().Set(test->ShouldContinue());
19981 v8::Isolate* isolate_;
19982 v8::base::Semaphore sem_;
19984 bool should_continue_;
19988 class RequestInterruptTestBaseWithSimpleInterrupt
19989 : public RequestInterruptTestBase {
19991 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
19993 virtual void StartInterruptThread() {
19998 class InterruptThread : public v8::base::Thread {
20000 explicit InterruptThread(RequestInterruptTestBase* test)
20001 : Thread(Options("RequestInterruptTest")), test_(test) {}
20003 virtual void Run() {
20004 test_->sem_.Wait();
20005 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
20008 static void OnInterrupt(v8::Isolate* isolate, void* data) {
20009 reinterpret_cast<RequestInterruptTestBase*>(data)->
20010 should_continue_ = false;
20014 RequestInterruptTestBase* test_;
20017 InterruptThread i_thread;
20021 class RequestInterruptTestWithFunctionCall
20022 : public RequestInterruptTestBaseWithSimpleInterrupt {
20024 virtual void TestBody() {
20025 Local<Function> func = Function::New(
20026 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
20027 env_->Global()->Set(v8_str("ShouldContinue"), func);
20029 i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops.
20030 CompileRun("while (ShouldContinue()) { }");
20035 class RequestInterruptTestWithMethodCall
20036 : public RequestInterruptTestBaseWithSimpleInterrupt {
20038 virtual void TestBody() {
20039 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20040 v8::Local<v8::Template> proto = t->PrototypeTemplate();
20041 proto->Set(v8_str("shouldContinue"), Function::New(
20042 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
20043 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20045 i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops.
20046 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
20051 class RequestInterruptTestWithAccessor
20052 : public RequestInterruptTestBaseWithSimpleInterrupt {
20054 virtual void TestBody() {
20055 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20056 v8::Local<v8::Template> proto = t->PrototypeTemplate();
20057 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
20058 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
20059 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20061 i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops.
20062 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
20067 class RequestInterruptTestWithNativeAccessor
20068 : public RequestInterruptTestBaseWithSimpleInterrupt {
20070 virtual void TestBody() {
20071 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20072 t->InstanceTemplate()->SetNativeDataProperty(
20073 v8_str("shouldContinue"),
20074 &ShouldContinueNativeGetter,
20076 v8::External::New(isolate_, this));
20077 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20079 i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops.
20080 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
20084 static void ShouldContinueNativeGetter(
20085 Local<String> property,
20086 const v8::PropertyCallbackInfo<v8::Value>& info) {
20087 RequestInterruptTestBase* test =
20088 reinterpret_cast<RequestInterruptTestBase*>(
20089 info.Data().As<v8::External>()->Value());
20090 info.GetReturnValue().Set(test->ShouldContinue());
20095 class RequestInterruptTestWithMethodCallAndInterceptor
20096 : public RequestInterruptTestBaseWithSimpleInterrupt {
20098 virtual void TestBody() {
20099 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20100 v8::Local<v8::Template> proto = t->PrototypeTemplate();
20101 proto->Set(v8_str("shouldContinue"), Function::New(
20102 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
20103 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
20104 instance_template->SetHandler(
20105 v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
20107 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20109 i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops.
20110 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
20114 static void EmptyInterceptor(
20115 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
20119 class RequestInterruptTestWithMathAbs
20120 : public RequestInterruptTestBaseWithSimpleInterrupt {
20122 virtual void TestBody() {
20123 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
20125 WakeUpInterruptorCallback,
20126 v8::External::New(isolate_, this)));
20128 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
20130 ShouldContinueCallback,
20131 v8::External::New(isolate_, this)));
20133 i::FLAG_allow_natives_syntax = true;
20134 i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops.
20135 CompileRun("function loopish(o) {"
20137 " while (o.abs(1) > 0) {"
20138 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
20140 " if (--pre === 0) WakeUpInterruptor(o === Math);"
20145 "var obj = {abs: function () { return i-- }, x: null};"
20148 "%OptimizeFunctionOnNextCall(loopish);"
20151 i::FLAG_allow_natives_syntax = false;
20155 static void WakeUpInterruptorCallback(
20156 const v8::FunctionCallbackInfo<Value>& info) {
20157 if (!info[0]->BooleanValue()) return;
20159 RequestInterruptTestBase* test =
20160 reinterpret_cast<RequestInterruptTestBase*>(
20161 info.Data().As<v8::External>()->Value());
20162 test->WakeUpInterruptor();
20165 static void ShouldContinueCallback(
20166 const v8::FunctionCallbackInfo<Value>& info) {
20167 RequestInterruptTestBase* test =
20168 reinterpret_cast<RequestInterruptTestBase*>(
20169 info.Data().As<v8::External>()->Value());
20170 info.GetReturnValue().Set(test->should_continue());
20175 TEST(RequestInterruptTestWithFunctionCall) {
20176 RequestInterruptTestWithFunctionCall().RunTest();
20180 TEST(RequestInterruptTestWithMethodCall) {
20181 RequestInterruptTestWithMethodCall().RunTest();
20185 TEST(RequestInterruptTestWithAccessor) {
20186 RequestInterruptTestWithAccessor().RunTest();
20190 TEST(RequestInterruptTestWithNativeAccessor) {
20191 RequestInterruptTestWithNativeAccessor().RunTest();
20195 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
20196 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
20200 TEST(RequestInterruptTestWithMathAbs) {
20201 RequestInterruptTestWithMathAbs().RunTest();
20205 class RequestMultipleInterrupts : public RequestInterruptTestBase {
20207 RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
20209 virtual void StartInterruptThread() {
20213 virtual void TestBody() {
20214 Local<Function> func = Function::New(
20215 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
20216 env_->Global()->Set(v8_str("ShouldContinue"), func);
20218 i::FLAG_turbo_osr = false; // TODO(titzer): interrupts in TF loops.
20219 CompileRun("while (ShouldContinue()) { }");
20223 class InterruptThread : public v8::base::Thread {
20225 enum { NUM_INTERRUPTS = 10 };
20226 explicit InterruptThread(RequestMultipleInterrupts* test)
20227 : Thread(Options("RequestInterruptTest")), test_(test) {}
20229 virtual void Run() {
20230 test_->sem_.Wait();
20231 for (int i = 0; i < NUM_INTERRUPTS; i++) {
20232 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
20236 static void OnInterrupt(v8::Isolate* isolate, void* data) {
20237 RequestMultipleInterrupts* test =
20238 reinterpret_cast<RequestMultipleInterrupts*>(data);
20239 test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
20243 RequestMultipleInterrupts* test_;
20246 InterruptThread i_thread;
20251 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
20254 static Local<Value> function_new_expected_env;
20255 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
20256 CHECK(function_new_expected_env->Equals(info.Data()));
20257 info.GetReturnValue().Set(17);
20261 THREADED_TEST(FunctionNew) {
20263 v8::Isolate* isolate = env->GetIsolate();
20264 v8::HandleScope scope(isolate);
20265 Local<Object> data = v8::Object::New(isolate);
20266 function_new_expected_env = data;
20267 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
20268 env->Global()->Set(v8_str("func"), func);
20269 Local<Value> result = CompileRun("func();");
20270 CHECK(v8::Integer::New(isolate, 17)->Equals(result));
20271 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20272 // Verify function not cached
20273 auto serial_number = handle(i::Smi::cast(v8::Utils::OpenHandle(*func)
20275 ->get_api_func_data()
20276 ->serial_number()),
20278 auto cache = i_isolate->function_cache();
20279 CHECK(cache->Lookup(serial_number)->IsTheHole());
20280 // Verify that each Function::New creates a new function instance
20281 Local<Object> data2 = v8::Object::New(isolate);
20282 function_new_expected_env = data2;
20283 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
20284 CHECK(!func2->IsNull());
20285 CHECK(!func->Equals(func2));
20286 env->Global()->Set(v8_str("func2"), func2);
20287 Local<Value> result2 = CompileRun("func2();");
20288 CHECK(v8::Integer::New(isolate, 17)->Equals(result2));
20292 TEST(EscapeableHandleScope) {
20293 HandleScope outer_scope(CcTest::isolate());
20294 LocalContext context;
20295 const int runs = 10;
20296 Local<String> values[runs];
20297 for (int i = 0; i < runs; i++) {
20298 v8::EscapableHandleScope inner_scope(CcTest::isolate());
20299 Local<String> value;
20300 if (i != 0) value = v8_str("escape value");
20301 values[i] = inner_scope.Escape(value);
20303 for (int i = 0; i < runs; i++) {
20304 Local<String> expected;
20306 CHECK(v8_str("escape value")->Equals(values[i]));
20308 CHECK(values[i].IsEmpty());
20314 static void SetterWhichExpectsThisAndHolderToDiffer(
20315 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
20316 CHECK(info.Holder() != info.This());
20320 TEST(Regress239669) {
20321 LocalContext context;
20322 v8::Isolate* isolate = context->GetIsolate();
20323 v8::HandleScope scope(isolate);
20324 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20325 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
20326 context->Global()->Set(v8_str("P"), templ->NewInstance());
20331 "C1.prototype = P;"
20332 "for (var i = 0; i < 4; i++ ) {"
20338 class ApiCallOptimizationChecker {
20340 static Local<Object> data;
20341 static Local<Object> receiver;
20342 static Local<Object> holder;
20343 static Local<Object> callee;
20346 static void OptimizationCallback(
20347 const v8::FunctionCallbackInfo<v8::Value>& info) {
20348 CHECK(callee == info.Callee());
20349 CHECK(data == info.Data());
20350 CHECK(receiver == info.This());
20351 if (info.Length() == 1) {
20352 CHECK(v8_num(1)->Equals(info[0]));
20354 CHECK(holder == info.Holder());
20356 info.GetReturnValue().Set(v8_str("returned"));
20360 enum SignatureType {
20362 kSignatureOnReceiver,
20363 kSignatureOnPrototype
20367 SignatureType signature_types[] =
20368 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
20369 for (unsigned i = 0; i < arraysize(signature_types); i++) {
20370 SignatureType signature_type = signature_types[i];
20371 for (int j = 0; j < 2; j++) {
20372 bool global = j == 0;
20373 int key = signature_type +
20374 arraysize(signature_types) * (global ? 1 : 0);
20375 Run(signature_type, global, key);
20380 void Run(SignatureType signature_type, bool global, int key) {
20381 v8::Isolate* isolate = CcTest::isolate();
20382 v8::HandleScope scope(isolate);
20383 // Build a template for signature checks.
20384 Local<v8::ObjectTemplate> signature_template;
20385 Local<v8::Signature> signature;
20387 Local<v8::FunctionTemplate> parent_template =
20388 FunctionTemplate::New(isolate);
20389 parent_template->SetHiddenPrototype(true);
20390 Local<v8::FunctionTemplate> function_template
20391 = FunctionTemplate::New(isolate);
20392 function_template->Inherit(parent_template);
20393 switch (signature_type) {
20396 case kSignatureOnReceiver:
20397 signature = v8::Signature::New(isolate, function_template);
20399 case kSignatureOnPrototype:
20400 signature = v8::Signature::New(isolate, parent_template);
20403 signature_template = function_template->InstanceTemplate();
20405 // Global object must pass checks.
20406 Local<v8::Context> context =
20407 v8::Context::New(isolate, NULL, signature_template);
20408 v8::Context::Scope context_scope(context);
20409 // Install regular object that can pass signature checks.
20410 Local<Object> function_receiver = signature_template->NewInstance();
20411 context->Global()->Set(v8_str("function_receiver"), function_receiver);
20412 // Get the holder objects.
20413 Local<Object> inner_global =
20414 Local<Object>::Cast(context->Global()->GetPrototype());
20415 // Install functions on hidden prototype object if there is one.
20416 data = Object::New(isolate);
20417 Local<FunctionTemplate> function_template = FunctionTemplate::New(
20418 isolate, OptimizationCallback, data, signature);
20419 Local<Function> function = function_template->GetFunction();
20420 Local<Object> global_holder = inner_global;
20421 Local<Object> function_holder = function_receiver;
20422 if (signature_type == kSignatureOnPrototype) {
20423 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
20424 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
20426 global_holder->Set(v8_str("g_f"), function);
20427 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
20428 function_holder->Set(v8_str("f"), function);
20429 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
20430 // Initialize expected values.
20434 receiver = context->Global();
20435 holder = inner_global;
20437 holder = function_receiver;
20438 // If not using a signature, add something else to the prototype chain
20439 // to test the case that holder != receiver
20440 if (signature_type == kNoSignature) {
20441 receiver = Local<Object>::Cast(CompileRun(
20442 "var receiver_subclass = {};\n"
20443 "receiver_subclass.__proto__ = function_receiver;\n"
20444 "receiver_subclass"));
20446 receiver = Local<Object>::Cast(CompileRun(
20447 "var receiver_subclass = function_receiver;\n"
20448 "receiver_subclass"));
20451 // With no signature, the holder is not set.
20452 if (signature_type == kNoSignature) holder = receiver;
20453 // build wrap_function
20454 i::ScopedVector<char> wrap_function(200);
20458 "function wrap_f_%d() { var f = g_f; return f(); }\n"
20459 "function wrap_get_%d() { return this.g_acc; }\n"
20460 "function wrap_set_%d() { return this.g_acc = 1; }\n",
20465 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
20466 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
20467 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
20470 // build source string
20471 i::ScopedVector<char> source(1000);
20474 "%s\n" // wrap functions
20475 "function wrap_f() { return wrap_f_%d(); }\n"
20476 "function wrap_get() { return wrap_get_%d(); }\n"
20477 "function wrap_set() { return wrap_set_%d(); }\n"
20478 "check = function(returned) {\n"
20479 " if (returned !== 'returned') { throw returned; }\n"
20482 "check(wrap_f());\n"
20483 "check(wrap_f());\n"
20484 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
20485 "check(wrap_f());\n"
20487 "check(wrap_get());\n"
20488 "check(wrap_get());\n"
20489 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
20490 "check(wrap_get());\n"
20492 "check = function(returned) {\n"
20493 " if (returned !== 1) { throw returned; }\n"
20495 "check(wrap_set());\n"
20496 "check(wrap_set());\n"
20497 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
20498 "check(wrap_set());\n",
20499 wrap_function.start(), key, key, key, key, key, key);
20500 v8::TryCatch try_catch;
20501 CompileRun(source.start());
20502 DCHECK(!try_catch.HasCaught());
20503 CHECK_EQ(9, count);
20508 Local<Object> ApiCallOptimizationChecker::data;
20509 Local<Object> ApiCallOptimizationChecker::receiver;
20510 Local<Object> ApiCallOptimizationChecker::holder;
20511 Local<Object> ApiCallOptimizationChecker::callee;
20512 int ApiCallOptimizationChecker::count = 0;
20515 TEST(FunctionCallOptimization) {
20516 i::FLAG_allow_natives_syntax = true;
20517 ApiCallOptimizationChecker checker;
20522 TEST(FunctionCallOptimizationMultipleArgs) {
20523 i::FLAG_allow_natives_syntax = true;
20524 LocalContext context;
20525 v8::Isolate* isolate = context->GetIsolate();
20526 v8::HandleScope scope(isolate);
20527 Handle<Object> global = context->Global();
20528 Local<v8::Function> function = Function::New(isolate, Returns42);
20529 global->Set(v8_str("x"), function);
20531 "function x_wrap() {\n"
20532 " for (var i = 0; i < 5; i++) {\n"
20537 "%OptimizeFunctionOnNextCall(x_wrap);"
20542 static void ReturnsSymbolCallback(
20543 const v8::FunctionCallbackInfo<v8::Value>& info) {
20544 info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
20548 TEST(ApiCallbackCanReturnSymbols) {
20549 i::FLAG_allow_natives_syntax = true;
20550 LocalContext context;
20551 v8::Isolate* isolate = context->GetIsolate();
20552 v8::HandleScope scope(isolate);
20553 Handle<Object> global = context->Global();
20554 Local<v8::Function> function = Function::New(isolate, ReturnsSymbolCallback);
20555 global->Set(v8_str("x"), function);
20557 "function x_wrap() {\n"
20558 " for (var i = 0; i < 5; i++) {\n"
20563 "%OptimizeFunctionOnNextCall(x_wrap);"
20568 TEST(EmptyApiCallback) {
20569 LocalContext context;
20570 auto isolate = context->GetIsolate();
20571 v8::HandleScope scope(isolate);
20572 auto global = context->Global();
20573 auto function = FunctionTemplate::New(isolate)->GetFunction();
20574 global->Set(v8_str("x"), function);
20576 auto result = CompileRun("x()");
20577 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20579 result = CompileRun("x(1,2,3)");
20580 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20582 result = CompileRun("7 + x.call(3) + 11");
20583 CHECK(result->IsInt32());
20584 CHECK_EQ(21, result->Int32Value());
20586 result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
20587 CHECK(result->IsInt32());
20588 CHECK_EQ(21, result->Int32Value());
20590 result = CompileRun("var y = []; x.call(y)");
20591 CHECK(result->IsArray());
20593 result = CompileRun("x.call(y, 1, 2, 3, 4)");
20594 CHECK(result->IsArray());
20598 TEST(SimpleSignatureCheck) {
20599 LocalContext context;
20600 auto isolate = context->GetIsolate();
20601 v8::HandleScope scope(isolate);
20602 auto global = context->Global();
20603 auto sig_obj = FunctionTemplate::New(isolate);
20604 auto sig = v8::Signature::New(isolate, sig_obj);
20605 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20606 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20607 global->Set(v8_str("x"), x->GetFunction());
20608 CompileRun("var s = new sig_obj();");
20610 TryCatch try_catch(isolate);
20612 CHECK(try_catch.HasCaught());
20615 TryCatch try_catch(isolate);
20616 CompileRun("x.call(1)");
20617 CHECK(try_catch.HasCaught());
20620 TryCatch try_catch(isolate);
20621 auto result = CompileRun("s.x = x; s.x()");
20622 CHECK(!try_catch.HasCaught());
20623 CHECK_EQ(42, result->Int32Value());
20626 TryCatch try_catch(isolate);
20627 auto result = CompileRun("x.call(s)");
20628 CHECK(!try_catch.HasCaught());
20629 CHECK_EQ(42, result->Int32Value());
20634 TEST(ChainSignatureCheck) {
20635 LocalContext context;
20636 auto isolate = context->GetIsolate();
20637 v8::HandleScope scope(isolate);
20638 auto global = context->Global();
20639 auto sig_obj = FunctionTemplate::New(isolate);
20640 auto sig = v8::Signature::New(isolate, sig_obj);
20641 for (int i = 0; i < 4; ++i) {
20642 auto temp = FunctionTemplate::New(isolate);
20643 temp->Inherit(sig_obj);
20646 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20647 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20648 global->Set(v8_str("x"), x->GetFunction());
20649 CompileRun("var s = new sig_obj();");
20651 TryCatch try_catch(isolate);
20653 CHECK(try_catch.HasCaught());
20656 TryCatch try_catch(isolate);
20657 CompileRun("x.call(1)");
20658 CHECK(try_catch.HasCaught());
20661 TryCatch try_catch(isolate);
20662 auto result = CompileRun("s.x = x; s.x()");
20663 CHECK(!try_catch.HasCaught());
20664 CHECK_EQ(42, result->Int32Value());
20667 TryCatch try_catch(isolate);
20668 auto result = CompileRun("x.call(s)");
20669 CHECK(!try_catch.HasCaught());
20670 CHECK_EQ(42, result->Int32Value());
20675 TEST(PrototypeSignatureCheck) {
20676 LocalContext context;
20677 auto isolate = context->GetIsolate();
20678 v8::HandleScope scope(isolate);
20679 auto global = context->Global();
20680 auto sig_obj = FunctionTemplate::New(isolate);
20681 sig_obj->SetHiddenPrototype(true);
20682 auto sig = v8::Signature::New(isolate, sig_obj);
20683 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20684 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20685 global->Set(v8_str("x"), x->GetFunction());
20686 CompileRun("s = {}; s.__proto__ = new sig_obj();");
20688 TryCatch try_catch(isolate);
20690 CHECK(try_catch.HasCaught());
20693 TryCatch try_catch(isolate);
20694 CompileRun("x.call(1)");
20695 CHECK(try_catch.HasCaught());
20698 TryCatch try_catch(isolate);
20699 auto result = CompileRun("s.x = x; s.x()");
20700 CHECK(!try_catch.HasCaught());
20701 CHECK_EQ(42, result->Int32Value());
20704 TryCatch try_catch(isolate);
20705 auto result = CompileRun("x.call(s)");
20706 CHECK(!try_catch.HasCaught());
20707 CHECK_EQ(42, result->Int32Value());
20712 static const char* last_event_message;
20713 static int last_event_status;
20714 void StoringEventLoggerCallback(const char* message, int status) {
20715 last_event_message = message;
20716 last_event_status = status;
20720 TEST(EventLogging) {
20721 v8::Isolate* isolate = CcTest::isolate();
20722 isolate->SetEventLogger(StoringEventLoggerCallback);
20723 v8::internal::HistogramTimer histogramTimer(
20724 "V8.Test", 0, 10000, v8::internal::HistogramTimer::MILLISECOND, 50,
20725 reinterpret_cast<v8::internal::Isolate*>(isolate));
20726 histogramTimer.Start();
20727 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20728 CHECK_EQ(0, last_event_status);
20729 histogramTimer.Stop();
20730 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20731 CHECK_EQ(1, last_event_status);
20736 LocalContext context;
20737 v8::Isolate* isolate = context->GetIsolate();
20738 v8::HandleScope scope(isolate);
20739 Handle<Object> global = context->Global();
20742 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20743 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
20744 Handle<v8::Promise> p = pr->GetPromise();
20745 Handle<v8::Promise> r = rr->GetPromise();
20746 CHECK_EQ(isolate, p->GetIsolate());
20748 // IsPromise predicate.
20749 CHECK(p->IsPromise());
20750 CHECK(r->IsPromise());
20751 Handle<Value> o = v8::Object::New(isolate);
20752 CHECK(!o->IsPromise());
20754 // Resolution and rejection.
20755 pr->Resolve(v8::Integer::New(isolate, 1));
20756 CHECK(p->IsPromise());
20757 rr->Reject(v8::Integer::New(isolate, 2));
20758 CHECK(r->IsPromise());
20760 // Chaining non-pending promises.
20764 "function f1(x) { x1 = x; return x+1 };\n"
20765 "function f2(x) { x2 = x; return x+1 };\n");
20766 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20767 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20770 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20771 isolate->RunMicrotasks();
20772 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20775 isolate->RunMicrotasks();
20776 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20779 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20780 isolate->RunMicrotasks();
20781 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20784 isolate->RunMicrotasks();
20785 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20787 // Chaining pending promises.
20788 CompileRun("x1 = x2 = 0;");
20789 pr = v8::Promise::Resolver::New(isolate);
20790 rr = v8::Promise::Resolver::New(isolate);
20792 pr->GetPromise()->Chain(f1);
20793 rr->GetPromise()->Catch(f2);
20794 isolate->RunMicrotasks();
20795 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20796 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20798 pr->Resolve(v8::Integer::New(isolate, 1));
20799 rr->Reject(v8::Integer::New(isolate, 2));
20800 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20801 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20803 isolate->RunMicrotasks();
20804 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20805 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20808 CompileRun("x1 = x2 = 0;");
20809 pr = v8::Promise::Resolver::New(isolate);
20810 pr->GetPromise()->Chain(f1)->Chain(f2);
20811 pr->Resolve(v8::Integer::New(isolate, 3));
20812 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20813 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20814 isolate->RunMicrotasks();
20815 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20816 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20818 CompileRun("x1 = x2 = 0;");
20819 rr = v8::Promise::Resolver::New(isolate);
20820 rr->GetPromise()->Catch(f1)->Chain(f2);
20821 rr->Reject(v8::Integer::New(isolate, 3));
20822 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20823 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20824 isolate->RunMicrotasks();
20825 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20826 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20830 TEST(PromiseThen) {
20831 LocalContext context;
20832 v8::Isolate* isolate = context->GetIsolate();
20833 v8::HandleScope scope(isolate);
20834 Handle<Object> global = context->Global();
20837 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20838 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
20839 Handle<v8::Promise> p = pr->GetPromise();
20840 Handle<v8::Promise> q = qr->GetPromise();
20842 CHECK(p->IsPromise());
20843 CHECK(q->IsPromise());
20845 pr->Resolve(v8::Integer::New(isolate, 1));
20848 // Chaining non-pending promises.
20852 "function f1(x) { x1 = x; return x+1 };\n"
20853 "function f2(x) { x2 = x; return x+1 };\n");
20854 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20855 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20859 CHECK(global->Get(v8_str("x1"))->IsNumber());
20860 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20861 isolate->RunMicrotasks();
20862 CHECK(!global->Get(v8_str("x1"))->IsNumber());
20863 CHECK(p->Equals(global->Get(v8_str("x1"))));
20866 CompileRun("x1 = x2 = 0;");
20868 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20869 isolate->RunMicrotasks();
20870 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20873 CompileRun("x1 = x2 = 0;");
20874 pr = v8::Promise::Resolver::New(isolate);
20875 qr = v8::Promise::Resolver::New(isolate);
20878 qr->GetPromise()->Then(f1)->Then(f2);
20880 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20881 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20882 isolate->RunMicrotasks();
20883 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20884 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20886 pr->Resolve(v8::Integer::New(isolate, 3));
20888 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20889 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20890 isolate->RunMicrotasks();
20891 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20892 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20896 TEST(DisallowJavascriptExecutionScope) {
20897 LocalContext context;
20898 v8::Isolate* isolate = context->GetIsolate();
20899 v8::HandleScope scope(isolate);
20900 v8::Isolate::DisallowJavascriptExecutionScope no_js(
20901 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20906 TEST(AllowJavascriptExecutionScope) {
20907 LocalContext context;
20908 v8::Isolate* isolate = context->GetIsolate();
20909 v8::HandleScope scope(isolate);
20910 v8::Isolate::DisallowJavascriptExecutionScope no_js(
20911 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20912 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20913 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20914 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
20920 TEST(ThrowOnJavascriptExecution) {
20921 LocalContext context;
20922 v8::Isolate* isolate = context->GetIsolate();
20923 v8::HandleScope scope(isolate);
20924 v8::TryCatch try_catch;
20925 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20926 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20928 CHECK(try_catch.HasCaught());
20932 TEST(Regress354123) {
20933 LocalContext current;
20934 v8::Isolate* isolate = current->GetIsolate();
20935 v8::HandleScope scope(isolate);
20937 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
20938 templ->SetAccessCheckCallbacks(AccessCounter, NULL);
20939 current->Global()->Set(v8_str("friend"), templ->NewInstance());
20941 // Test access using __proto__ from the prototype chain.
20943 CompileRun("friend.__proto__ = {};");
20944 CHECK_EQ(2, access_count);
20945 CompileRun("friend.__proto__;");
20946 CHECK_EQ(4, access_count);
20948 // Test access using __proto__ as a hijacked function (A).
20950 CompileRun("var p = Object.prototype;"
20951 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
20952 "f.call(friend, {});");
20953 CHECK_EQ(1, access_count);
20954 CompileRun("var p = Object.prototype;"
20955 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
20956 "f.call(friend);");
20957 CHECK_EQ(2, access_count);
20959 // Test access using __proto__ as a hijacked function (B).
20961 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
20962 "f.call(friend, {});");
20963 CHECK_EQ(1, access_count);
20964 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
20965 "f.call(friend);");
20966 CHECK_EQ(2, access_count);
20968 // Test access using Object.setPrototypeOf reflective method.
20970 CompileRun("Object.setPrototypeOf(friend, {});");
20971 CHECK_EQ(1, access_count);
20972 CompileRun("Object.getPrototypeOf(friend);");
20973 CHECK_EQ(2, access_count);
20977 TEST(CaptureStackTraceForStackOverflow) {
20978 v8::internal::FLAG_stack_size = 150;
20979 LocalContext current;
20980 v8::Isolate* isolate = current->GetIsolate();
20981 v8::HandleScope scope(isolate);
20982 V8::SetCaptureStackTraceForUncaughtExceptions(
20983 true, 10, v8::StackTrace::kDetailed);
20984 v8::TryCatch try_catch;
20985 CompileRun("(function f(x) { f(x+1); })(0)");
20986 CHECK(try_catch.HasCaught());
20990 TEST(ScriptNameAndLineNumber) {
20992 v8::Isolate* isolate = env->GetIsolate();
20993 v8::HandleScope scope(isolate);
20994 const char* url = "http://www.foo.com/foo.js";
20995 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
20996 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
20997 Local<Script> script = v8::ScriptCompiler::Compile(
20998 isolate, &script_source);
20999 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
21000 CHECK(!script_name.IsEmpty());
21001 CHECK(script_name->IsString());
21002 String::Utf8Value utf8_name(script_name);
21003 CHECK_EQ(0, strcmp(url, *utf8_name));
21004 int line_number = script->GetUnboundScript()->GetLineNumber(0);
21005 CHECK_EQ(13, line_number);
21008 void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
21009 const char* expected_source_mapping_url) {
21010 if (expected_source_url != NULL) {
21011 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
21012 CHECK_EQ(0, strcmp(expected_source_url, *url));
21014 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
21016 if (expected_source_mapping_url != NULL) {
21017 v8::String::Utf8Value url(
21018 script->GetUnboundScript()->GetSourceMappingURL());
21019 CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
21021 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
21025 void SourceURLHelper(const char* source, const char* expected_source_url,
21026 const char* expected_source_mapping_url) {
21027 Local<Script> script = v8_compile(source);
21028 CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
21032 TEST(ScriptSourceURLAndSourceMappingURL) {
21034 v8::Isolate* isolate = env->GetIsolate();
21035 v8::HandleScope scope(isolate);
21036 SourceURLHelper("function foo() {}\n"
21037 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
21038 SourceURLHelper("function foo() {}\n"
21039 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
21041 // Both sourceURL and sourceMappingURL.
21042 SourceURLHelper("function foo() {}\n"
21043 "//# sourceURL=bar3.js\n"
21044 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
21046 // Two source URLs; the first one is ignored.
21047 SourceURLHelper("function foo() {}\n"
21048 "//# sourceURL=ignoreme.js\n"
21049 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
21050 SourceURLHelper("function foo() {}\n"
21051 "//# sourceMappingURL=ignoreme.js\n"
21052 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
21054 // SourceURL or sourceMappingURL in the middle of the script.
21055 SourceURLHelper("function foo() {}\n"
21056 "//# sourceURL=bar7.js\n"
21057 "function baz() {}\n", "bar7.js", NULL);
21058 SourceURLHelper("function foo() {}\n"
21059 "//# sourceMappingURL=bar8.js\n"
21060 "function baz() {}\n", NULL, "bar8.js");
21062 // Too much whitespace.
21063 SourceURLHelper("function foo() {}\n"
21064 "//# sourceURL=bar9.js\n"
21065 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
21066 SourceURLHelper("function foo() {}\n"
21067 "//# sourceURL =bar11.js\n"
21068 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
21070 // Disallowed characters in value.
21071 SourceURLHelper("function foo() {}\n"
21072 "//# sourceURL=bar13 .js \n"
21073 "//# sourceMappingURL=bar14 .js \n",
21075 SourceURLHelper("function foo() {}\n"
21076 "//# sourceURL=bar15\t.js \n"
21077 "//# sourceMappingURL=bar16\t.js \n",
21079 SourceURLHelper("function foo() {}\n"
21080 "//# sourceURL=bar17'.js \n"
21081 "//# sourceMappingURL=bar18'.js \n",
21083 SourceURLHelper("function foo() {}\n"
21084 "//# sourceURL=bar19\".js \n"
21085 "//# sourceMappingURL=bar20\".js \n",
21088 // Not too much whitespace.
21089 SourceURLHelper("function foo() {}\n"
21090 "//# sourceURL= bar21.js \n"
21091 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
21095 TEST(GetOwnPropertyDescriptor) {
21097 v8::Isolate* isolate = env->GetIsolate();
21098 v8::HandleScope scope(isolate);
21100 "var x = { value : 13};"
21101 "Object.defineProperty(x, 'p0', {value : 12});"
21102 "Object.defineProperty(x, 'p1', {"
21103 " set : function(value) { this.value = value; },"
21104 " get : function() { return this.value; },"
21106 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
21107 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
21108 CHECK(desc->IsUndefined());
21109 desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
21110 CHECK(v8_num(12)->Equals(Local<Object>::Cast(desc)->Get(v8_str("value"))));
21111 desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
21112 Local<Function> set =
21113 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
21114 Local<Function> get =
21115 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
21116 CHECK(v8_num(13)->Equals(get->Call(x, 0, NULL)));
21117 Handle<Value> args[] = { v8_num(14) };
21118 set->Call(x, 1, args);
21119 CHECK(v8_num(14)->Equals(get->Call(x, 0, NULL)));
21123 TEST(Regress411877) {
21124 v8::Isolate* isolate = CcTest::isolate();
21125 v8::HandleScope handle_scope(isolate);
21126 v8::Handle<v8::ObjectTemplate> object_template =
21127 v8::ObjectTemplate::New(isolate);
21128 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
21130 v8::Handle<Context> context = Context::New(isolate);
21131 v8::Context::Scope context_scope(context);
21133 context->Global()->Set(v8_str("o"), object_template->NewInstance());
21134 CompileRun("Object.getOwnPropertyNames(o)");
21138 TEST(GetHiddenPropertyTableAfterAccessCheck) {
21139 v8::Isolate* isolate = CcTest::isolate();
21140 v8::HandleScope handle_scope(isolate);
21141 v8::Handle<v8::ObjectTemplate> object_template =
21142 v8::ObjectTemplate::New(isolate);
21143 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
21145 v8::Handle<Context> context = Context::New(isolate);
21146 v8::Context::Scope context_scope(context);
21148 v8::Handle<v8::Object> obj = object_template->NewInstance();
21149 obj->Set(v8_str("key"), v8_str("value"));
21150 obj->Delete(v8_str("key"));
21152 obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
21156 TEST(Regress411793) {
21157 v8::Isolate* isolate = CcTest::isolate();
21158 v8::HandleScope handle_scope(isolate);
21159 v8::Handle<v8::ObjectTemplate> object_template =
21160 v8::ObjectTemplate::New(isolate);
21161 object_template->SetAccessCheckCallbacks(AccessCounter, NULL);
21163 v8::Handle<Context> context = Context::New(isolate);
21164 v8::Context::Scope context_scope(context);
21166 context->Global()->Set(v8_str("o"), object_template->NewInstance());
21168 "Object.defineProperty(o, 'key', "
21169 " { get: function() {}, set: function() {} });");
21172 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
21174 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
21176 virtual size_t GetMoreData(const uint8_t** src) {
21177 // Unlike in real use cases, this function will never block.
21178 if (chunks_[index_] == NULL) {
21181 // Copy the data, since the caller takes ownership of it.
21182 size_t len = strlen(chunks_[index_]);
21183 // We don't need to zero-terminate since we return the length.
21184 uint8_t* copy = new uint8_t[len];
21185 memcpy(copy, chunks_[index_], len);
21191 // Helper for constructing a string from chunks (the compilation needs it
21193 static char* FullSourceString(const char** chunks) {
21194 size_t total_len = 0;
21195 for (size_t i = 0; chunks[i] != NULL; ++i) {
21196 total_len += strlen(chunks[i]);
21198 char* full_string = new char[total_len + 1];
21200 for (size_t i = 0; chunks[i] != NULL; ++i) {
21201 size_t len = strlen(chunks[i]);
21202 memcpy(full_string + offset, chunks[i], len);
21205 full_string[total_len] = 0;
21206 return full_string;
21210 const char** chunks_;
21215 // Helper function for running streaming tests.
21216 void RunStreamingTest(const char** chunks,
21217 v8::ScriptCompiler::StreamedSource::Encoding encoding =
21218 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
21219 bool expected_success = true,
21220 const char* expected_source_url = NULL,
21221 const char* expected_source_mapping_url = NULL) {
21223 v8::Isolate* isolate = env->GetIsolate();
21224 v8::HandleScope scope(isolate);
21225 v8::TryCatch try_catch;
21227 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
21229 v8::ScriptCompiler::ScriptStreamingTask* task =
21230 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
21232 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
21233 // task here in the main thread.
21237 // Possible errors are only produced while compiling.
21238 CHECK_EQ(false, try_catch.HasCaught());
21240 v8::ScriptOrigin origin(v8_str("http://foo.com"));
21241 char* full_source = TestSourceStream::FullSourceString(chunks);
21242 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
21243 isolate, &source, v8_str(full_source), origin);
21244 if (expected_success) {
21245 CHECK(!script.IsEmpty());
21246 v8::Handle<Value> result(script->Run());
21247 // All scripts are supposed to return the fixed value 13 when ran.
21248 CHECK_EQ(13, result->Int32Value());
21249 CheckMagicComments(script, expected_source_url,
21250 expected_source_mapping_url);
21252 CHECK(script.IsEmpty());
21253 CHECK(try_catch.HasCaught());
21255 delete[] full_source;
21259 TEST(StreamingSimpleScript) {
21260 // This script is unrealistically small, since no one chunk is enough to fill
21261 // the backing buffer of Scanner, let alone overflow it.
21262 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
21264 RunStreamingTest(chunks);
21268 TEST(StreamingBiggerScript) {
21269 const char* chunk1 =
21270 "function foo() {\n"
21271 " // Make this chunk sufficiently long so that it will overflow the\n"
21272 " // backing buffer of the Scanner.\n"
21274 " var result = 0;\n"
21275 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21277 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21279 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21281 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21282 " return result;\n"
21284 const char* chunks[] = {chunk1, "foo(); ", NULL};
21285 RunStreamingTest(chunks);
21289 TEST(StreamingScriptWithParseError) {
21290 // Test that parse errors from streamed scripts are propagated correctly.
21293 " // This will result in a parse error.\n"
21294 " var if else then foo";
21295 char chunk2[] = " 13\n";
21296 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21298 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
21301 // Test that the next script succeeds normally.
21304 " // This will be parsed successfully.\n"
21305 " function foo() { return ";
21306 char chunk2[] = " 13; }\n";
21307 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21309 RunStreamingTest(chunks);
21314 TEST(StreamingUtf8Script) {
21315 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
21317 const char* chunk1 =
21318 "function foo() {\n"
21319 " // This function will contain an UTF-8 character which is not in\n"
21321 " var foob\xec\x92\x81r = 13;\n"
21322 " return foob\xec\x92\x81r;\n"
21324 const char* chunks[] = {chunk1, "foo(); ", NULL};
21325 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21329 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
21330 // A sanity check to prove that the approach of splitting UTF-8
21331 // characters is correct. Here is an UTF-8 character which will take three
21333 const char* reference = "\xec\x92\x81";
21334 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
21337 "function foo() {\n"
21338 " // This function will contain an UTF-8 character which is not in\n"
21343 " return foob\xec\x92\x81r;\n"
21345 for (int i = 0; i < 3; ++i) {
21346 chunk2[i] = reference[i];
21348 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21349 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21353 TEST(StreamingUtf8ScriptWithSplitCharacters) {
21354 // Stream data where a multi-byte UTF-8 character is split between two data
21356 const char* reference = "\xec\x92\x81";
21358 "function foo() {\n"
21359 " // This function will contain an UTF-8 character which is not in\n"
21364 " return foob\xec\x92\x81r;\n"
21366 chunk1[strlen(chunk1) - 1] = reference[0];
21367 chunk2[0] = reference[1];
21368 chunk2[1] = reference[2];
21369 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21370 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21374 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
21375 // Tests edge cases which should still be decoded correctly.
21377 // Case 1: a chunk contains only bytes for a split character (and no other
21378 // data). This kind of a chunk would be exceptionally small, but we should
21379 // still decode it correctly.
21380 const char* reference = "\xec\x92\x81";
21381 // The small chunk is at the beginning of the split character
21384 "function foo() {\n"
21385 " // This function will contain an UTF-8 character which is not in\n"
21388 char chunk2[] = "XX";
21391 " return foob\xec\x92\x81r;\n"
21393 chunk2[0] = reference[0];
21394 chunk2[1] = reference[1];
21395 chunk3[0] = reference[2];
21396 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
21397 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21399 // The small chunk is at the end of a character
21402 "function foo() {\n"
21403 " // This function will contain an UTF-8 character which is not in\n"
21406 char chunk2[] = "XX";
21409 " return foob\xec\x92\x81r;\n"
21411 chunk1[strlen(chunk1) - 1] = reference[0];
21412 chunk2[0] = reference[1];
21413 chunk2[1] = reference[2];
21414 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
21415 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21417 // Case 2: the script ends with a multi-byte character. Make sure that it's
21418 // decoded correctly and not just ignored.
21421 "var foob\xec\x92\x81 = 13;\n"
21422 "foob\xec\x92\x81";
21423 const char* chunks[] = {chunk1, NULL};
21424 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21429 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
21430 // Test cases where a UTF-8 character is split over several chunks. Those
21431 // cases are not supported (the embedder should give the data in big enough
21432 // chunks), but we shouldn't crash, just produce a parse error.
21433 const char* reference = "\xec\x92\x81";
21435 "function foo() {\n"
21436 " // This function will contain an UTF-8 character which is not in\n"
21439 char chunk2[] = "X";
21442 " return foob\xec\x92\x81r;\n"
21444 chunk1[strlen(chunk1) - 1] = reference[0];
21445 chunk2[0] = reference[1];
21446 chunk3[0] = reference[2];
21447 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
21449 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
21453 TEST(StreamingProducesParserCache) {
21454 i::FLAG_min_preparse_length = 0;
21455 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
21459 v8::Isolate* isolate = env->GetIsolate();
21460 v8::HandleScope scope(isolate);
21462 v8::ScriptCompiler::StreamedSource source(
21463 new TestSourceStream(chunks),
21464 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21465 v8::ScriptCompiler::ScriptStreamingTask* task =
21466 v8::ScriptCompiler::StartStreamingScript(
21467 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
21469 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
21470 // task here in the main thread.
21474 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
21475 CHECK(cached_data != NULL);
21476 CHECK(cached_data->data != NULL);
21477 CHECK(!cached_data->rejected);
21478 CHECK_GT(cached_data->length, 0);
21482 TEST(StreamingWithDebuggingDoesNotProduceParserCache) {
21483 // If the debugger is active, we should just not produce parser cache at
21484 // all. This is a regeression test: We used to produce a parser cache without
21485 // any data in it (just headers).
21486 i::FLAG_min_preparse_length = 0;
21487 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
21491 v8::Isolate* isolate = env->GetIsolate();
21492 v8::HandleScope scope(isolate);
21494 // Make the debugger active by setting a breakpoint.
21495 CompileRun("function break_here() { }");
21496 i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
21497 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("break_here"))));
21498 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
21500 debug->SetBreakPoint(func, i::Handle<i::Object>(v8::internal::Smi::FromInt(1),
21501 CcTest::i_isolate()),
21504 v8::ScriptCompiler::StreamedSource source(
21505 new TestSourceStream(chunks),
21506 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21507 v8::ScriptCompiler::ScriptStreamingTask* task =
21508 v8::ScriptCompiler::StartStreamingScript(
21509 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
21511 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
21512 // task here in the main thread.
21516 // Check that we got no cached data.
21517 CHECK(source.GetCachedData() == NULL);
21521 TEST(StreamingScriptWithInvalidUtf8) {
21522 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
21523 // chunk don't produce a crash.
21524 const char* reference = "\xec\x92\x81\x80\x80";
21526 "function foo() {\n"
21527 " // This function will contain an UTF-8 character which is not in\n"
21529 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
21532 " return foob\xec\x92\x81\x80\x80r;\n"
21534 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
21536 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21537 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
21541 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
21542 // Regression test: Stream data where there are several multi-byte UTF-8
21543 // characters in a sequence and one of them is split between two data chunks.
21544 const char* reference = "\xec\x92\x81";
21546 "function foo() {\n"
21547 " // This function will contain an UTF-8 character which is not in\n"
21549 " var foob\xec\x92\x81X";
21552 " return foob\xec\x92\x81\xec\x92\x81r;\n"
21554 chunk1[strlen(chunk1) - 1] = reference[0];
21555 chunk2[0] = reference[1];
21556 chunk2[1] = reference[2];
21557 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21558 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21562 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
21563 // Another regression test, similar to the previous one. The difference is
21564 // that the split character is not the last one in the sequence.
21565 const char* reference = "\xec\x92\x81";
21567 "function foo() {\n"
21568 " // This function will contain an UTF-8 character which is not in\n"
21572 "XX\xec\x92\x81r = 13;\n"
21573 " return foob\xec\x92\x81\xec\x92\x81r;\n"
21575 chunk1[strlen(chunk1) - 1] = reference[0];
21576 chunk2[0] = reference[1];
21577 chunk2[1] = reference[2];
21578 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21579 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21583 TEST(StreamingWithHarmonyScopes) {
21584 // Don't use RunStreamingTest here so that both scripts get to use the same
21585 // LocalContext and HandleScope.
21587 v8::Isolate* isolate = env->GetIsolate();
21588 v8::HandleScope scope(isolate);
21590 // First, run a script with a let variable.
21591 CompileRun("\"use strict\"; let x = 1;");
21593 // Then stream a script which (erroneously) tries to introduce the same
21595 const char* chunks[] = {"\"use strict\"; let x = 2;", NULL};
21597 v8::TryCatch try_catch;
21598 v8::ScriptCompiler::StreamedSource source(
21599 new TestSourceStream(chunks),
21600 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21601 v8::ScriptCompiler::ScriptStreamingTask* task =
21602 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
21606 // Parsing should succeed (the script will be parsed and compiled in a context
21607 // independent way, so the error is not detected).
21608 CHECK_EQ(false, try_catch.HasCaught());
21610 v8::ScriptOrigin origin(v8_str("http://foo.com"));
21611 char* full_source = TestSourceStream::FullSourceString(chunks);
21612 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
21613 isolate, &source, v8_str(full_source), origin);
21614 CHECK(!script.IsEmpty());
21615 CHECK_EQ(false, try_catch.HasCaught());
21617 // Running the script exposes the error.
21618 v8::Handle<Value> result(script->Run());
21619 CHECK(result.IsEmpty());
21620 CHECK(try_catch.HasCaught());
21621 delete[] full_source;
21625 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
21626 const char* garbage = "garbage garbage garbage garbage garbage garbage";
21627 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
21629 v8::ScriptCompiler::CachedData* cached_data =
21630 new v8::ScriptCompiler::CachedData(data, length);
21631 DCHECK(!cached_data->rejected);
21632 v8::ScriptOrigin origin(v8_str("origin"));
21633 v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
21634 v8::Handle<v8::Script> script =
21635 v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
21636 CHECK(cached_data->rejected);
21637 CHECK_EQ(42, script->Run()->Int32Value());
21641 TEST(InvalidCacheData) {
21642 v8::V8::Initialize();
21643 v8::HandleScope scope(CcTest::isolate());
21644 LocalContext context;
21645 TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
21646 TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
21650 TEST(ParserCacheRejectedGracefully) {
21651 i::FLAG_min_preparse_length = 0;
21652 v8::V8::Initialize();
21653 v8::HandleScope scope(CcTest::isolate());
21654 LocalContext context;
21655 // Produce valid cached data.
21656 v8::ScriptOrigin origin(v8_str("origin"));
21657 v8::Local<v8::String> source_str = v8_str("function foo() {}");
21658 v8::ScriptCompiler::Source source(source_str, origin);
21659 v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
21660 CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
21661 CHECK(!script.IsEmpty());
21662 const v8::ScriptCompiler::CachedData* original_cached_data =
21663 source.GetCachedData();
21664 CHECK(original_cached_data != NULL);
21665 CHECK(original_cached_data->data != NULL);
21666 CHECK(!original_cached_data->rejected);
21667 CHECK_GT(original_cached_data->length, 0);
21668 // Recompiling the same script with it won't reject the data.
21670 v8::ScriptCompiler::Source source_with_cached_data(
21671 source_str, origin,
21672 new v8::ScriptCompiler::CachedData(original_cached_data->data,
21673 original_cached_data->length));
21674 v8::Handle<v8::Script> script =
21675 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21676 v8::ScriptCompiler::kConsumeParserCache);
21677 CHECK(!script.IsEmpty());
21678 const v8::ScriptCompiler::CachedData* new_cached_data =
21679 source_with_cached_data.GetCachedData();
21680 CHECK(new_cached_data != NULL);
21681 CHECK(!new_cached_data->rejected);
21683 // Compile an incompatible script with the cached data. The new script doesn't
21684 // have the same starting position for the function as the old one, so the old
21685 // cached data will be incompatible with it and will be rejected.
21687 v8::Local<v8::String> incompatible_source_str =
21688 v8_str(" function foo() {}");
21689 v8::ScriptCompiler::Source source_with_cached_data(
21690 incompatible_source_str, origin,
21691 new v8::ScriptCompiler::CachedData(original_cached_data->data,
21692 original_cached_data->length));
21693 v8::Handle<v8::Script> script =
21694 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21695 v8::ScriptCompiler::kConsumeParserCache);
21696 CHECK(!script.IsEmpty());
21697 const v8::ScriptCompiler::CachedData* new_cached_data =
21698 source_with_cached_data.GetCachedData();
21699 CHECK(new_cached_data != NULL);
21700 CHECK(new_cached_data->rejected);
21705 TEST(StringConcatOverflow) {
21706 v8::V8::Initialize();
21707 v8::HandleScope scope(CcTest::isolate());
21708 RandomLengthOneByteResource* r =
21709 new RandomLengthOneByteResource(i::String::kMaxLength);
21710 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
21711 CHECK(!str.IsEmpty());
21712 v8::TryCatch try_catch;
21713 v8::Local<v8::String> result = v8::String::Concat(str, str);
21714 CHECK(result.IsEmpty());
21715 CHECK(!try_catch.HasCaught());
21719 TEST(TurboAsmDisablesNeuter) {
21720 v8::V8::Initialize();
21721 v8::HandleScope scope(CcTest::isolate());
21722 LocalContext context;
21723 #if V8_TURBOFAN_TARGET
21724 bool should_be_neuterable = !i::FLAG_turbo_asm;
21726 bool should_be_neuterable = true;
21729 "function Module(stdlib, foreign, heap) {"
21731 " var MEM32 = new stdlib.Int32Array(heap);"
21732 " function load() { return MEM32[0]; }"
21733 " return { load: load };"
21735 "var buffer = new ArrayBuffer(4);"
21736 "Module(this, {}, buffer).load();"
21739 i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF.
21740 v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
21741 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21743 const char* store =
21744 "function Module(stdlib, foreign, heap) {"
21746 " var MEM32 = new stdlib.Int32Array(heap);"
21747 " function store() { MEM32[0] = 0; }"
21748 " return { store: store };"
21750 "var buffer = new ArrayBuffer(4);"
21751 "Module(this, {}, buffer).store();"
21754 i::FLAG_turbo_osr = false; // TODO(titzer): test requires eager TF.
21755 result = CompileRun(store).As<v8::ArrayBuffer>();
21756 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21760 TEST(GetPrototypeAccessControl) {
21761 i::FLAG_allow_natives_syntax = true;
21762 v8::Isolate* isolate = CcTest::isolate();
21763 v8::HandleScope handle_scope(isolate);
21766 v8::Handle<v8::ObjectTemplate> obj_template =
21767 v8::ObjectTemplate::New(isolate);
21768 obj_template->SetAccessCheckCallbacks(AccessAlwaysBlocked, NULL);
21770 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
21773 v8::TryCatch try_catch;
21775 "function f() { %_GetPrototype(prohibited); }"
21776 "%OptimizeFunctionOnNextCall(f);"
21778 CHECK(try_catch.HasCaught());
21783 TEST(GetPrototypeHidden) {
21784 i::FLAG_allow_natives_syntax = true;
21785 v8::Isolate* isolate = CcTest::isolate();
21786 v8::HandleScope handle_scope(isolate);
21789 Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
21790 t->SetHiddenPrototype(true);
21791 Handle<Object> proto = t->GetFunction()->NewInstance();
21792 Handle<Object> object = Object::New(isolate);
21793 Handle<Object> proto2 = Object::New(isolate);
21794 object->SetPrototype(proto);
21795 proto->SetPrototype(proto2);
21797 env->Global()->Set(v8_str("object"), object);
21798 env->Global()->Set(v8_str("proto"), proto);
21799 env->Global()->Set(v8_str("proto2"), proto2);
21801 v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
21802 CHECK(result->Equals(proto2));
21804 result = CompileRun(
21805 "function f() { return %_GetPrototype(object); }"
21806 "%OptimizeFunctionOnNextCall(f);"
21808 CHECK(result->Equals(proto2));
21812 TEST(ClassPrototypeCreationContext) {
21813 i::FLAG_harmony_classes = true;
21814 v8::Isolate* isolate = CcTest::isolate();
21815 v8::HandleScope handle_scope(isolate);
21818 Handle<Object> result = Handle<Object>::Cast(
21819 CompileRun("'use strict'; class Example { }; Example.prototype"));
21820 CHECK(env.local() == result->CreationContext());
21824 TEST(SimpleStreamingScriptWithSourceURL) {
21825 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
21826 "//# sourceURL=bar2.js\n", NULL};
21827 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21832 TEST(StreamingScriptWithSplitSourceURL) {
21833 const char* chunks[] = {"function foo() { ret", "urn 13; } f",
21834 "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
21835 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21840 TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
21841 const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
21842 " sourceMappingURL=bar2.js\n", "foo();", NULL};
21843 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
21848 TEST(NewStringRangeError) {
21849 v8::Isolate* isolate = CcTest::isolate();
21850 v8::HandleScope handle_scope(isolate);
21851 const int length = i::String::kMaxLength + 1;
21852 const int buffer_size = length * sizeof(uint16_t);
21853 void* buffer = malloc(buffer_size);
21854 if (buffer == NULL) return;
21855 memset(buffer, 'A', buffer_size);
21857 v8::TryCatch try_catch;
21858 char* data = reinterpret_cast<char*>(buffer);
21859 CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString,
21860 length).IsEmpty());
21861 CHECK(!try_catch.HasCaught());
21864 v8::TryCatch try_catch;
21865 uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
21866 CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString,
21867 length).IsEmpty());
21868 CHECK(!try_catch.HasCaught());
21871 v8::TryCatch try_catch;
21872 uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
21873 CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString,
21874 length).IsEmpty());
21875 CHECK(!try_catch.HasCaught());
21881 TEST(SealHandleScope) {
21882 v8::Isolate* isolate = CcTest::isolate();
21883 v8::HandleScope handle_scope(isolate);
21886 v8::SealHandleScope seal(isolate);
21889 v8::Local<v8::Object> obj = v8::Object::New(isolate);
21895 TEST(SealHandleScopeNested) {
21896 v8::Isolate* isolate = CcTest::isolate();
21897 v8::HandleScope handle_scope(isolate);
21900 v8::SealHandleScope seal(isolate);
21903 v8::HandleScope handle_scope(isolate);
21906 v8::Local<v8::Object> obj = v8::Object::New(isolate);