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/snapshot.h"
49 #include "src/unicode-inl.h"
50 #include "src/utils.h"
51 #include "src/vm-state.h"
53 static const bool kLogThreading = false;
56 using ::v8::BooleanObject;
58 using ::v8::Extension;
60 using ::v8::FunctionTemplate;
62 using ::v8::HandleScope;
66 using ::v8::MessageCallback;
68 using ::v8::ObjectTemplate;
69 using ::v8::Persistent;
71 using ::v8::StackTrace;
75 using ::v8::Undefined;
81 #define THREADED_PROFILED_TEST(Name) \
82 static void Test##Name(); \
83 TEST(Name##WithProfiler) { \
84 RunWithProfiler(&Test##Name); \
89 void RunWithProfiler(void (*test)()) {
91 v8::HandleScope scope(env->GetIsolate());
92 v8::Local<v8::String> profile_name =
93 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
94 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
96 cpu_profiler->StartProfiling(profile_name);
98 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
102 static int signature_callback_count;
103 static Local<Value> signature_expected_receiver;
104 static void IncrementingSignatureCallback(
105 const v8::FunctionCallbackInfo<v8::Value>& args) {
106 ApiTestFuzzer::Fuzz();
107 signature_callback_count++;
108 CHECK(signature_expected_receiver->Equals(args.Holder()));
109 CHECK(signature_expected_receiver->Equals(args.This()));
110 v8::Handle<v8::Array> result =
111 v8::Array::New(args.GetIsolate(), args.Length());
112 for (int i = 0; i < args.Length(); i++)
113 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
114 args.GetReturnValue().Set(result);
118 static void Returns42(const v8::FunctionCallbackInfo<v8::Value>& info) {
119 info.GetReturnValue().Set(42);
123 // Tests that call v8::V8::Dispose() cannot be threaded.
124 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
125 CHECK(v8::V8::Initialize());
126 CHECK(v8::V8::Dispose());
130 // Tests that call v8::V8::Dispose() cannot be threaded.
131 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
132 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
133 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
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());
140 THREADED_TEST(Handles) {
141 v8::HandleScope scope(CcTest::isolate());
142 Local<Context> local_env;
145 local_env = env.local();
148 // Local context should still be live.
149 CHECK(!local_env.IsEmpty());
152 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
153 CHECK(!undef.IsEmpty());
154 CHECK(undef->IsUndefined());
156 const char* source = "1 + 2 + 3";
157 Local<Script> script = v8_compile(source);
158 CHECK_EQ(6, script->Run()->Int32Value());
164 THREADED_TEST(IsolateOfContext) {
165 v8::HandleScope scope(CcTest::isolate());
166 v8::Handle<Context> env = Context::New(CcTest::isolate());
168 CHECK(!env->GetIsolate()->InContext());
169 CHECK(env->GetIsolate() == CcTest::isolate());
171 CHECK(env->GetIsolate()->InContext());
172 CHECK(env->GetIsolate() == CcTest::isolate());
174 CHECK(!env->GetIsolate()->InContext());
175 CHECK(env->GetIsolate() == CcTest::isolate());
179 static void TestSignature(const char* loop_js, Local<Value> receiver,
180 v8::Isolate* isolate) {
181 i::ScopedVector<char> source(200);
183 "for (var i = 0; i < 10; i++) {"
187 signature_callback_count = 0;
188 signature_expected_receiver = receiver;
189 bool expected_to_throw = receiver.IsEmpty();
190 v8::TryCatch try_catch;
191 CompileRun(source.start());
192 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
193 if (!expected_to_throw) {
194 CHECK_EQ(10, signature_callback_count);
196 CHECK(v8_str("TypeError: Illegal invocation")
197 ->Equals(try_catch.Exception()->ToString(isolate)));
202 THREADED_TEST(ReceiverSignature) {
204 v8::Isolate* isolate = env->GetIsolate();
205 v8::HandleScope scope(isolate);
207 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
208 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
209 v8::Handle<v8::FunctionTemplate> callback_sig =
210 v8::FunctionTemplate::New(
211 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
212 v8::Handle<v8::FunctionTemplate> callback =
213 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
214 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
215 sub_fun->Inherit(fun);
216 v8::Handle<v8::FunctionTemplate> unrel_fun =
217 v8::FunctionTemplate::New(isolate);
218 // Install properties.
219 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
220 fun_proto->Set(v8_str("prop_sig"), callback_sig);
221 fun_proto->Set(v8_str("prop"), callback);
222 fun_proto->SetAccessorProperty(
223 v8_str("accessor_sig"), callback_sig, callback_sig);
224 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
225 // Instantiate templates.
226 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
227 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
228 // Setup global variables.
229 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
230 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
231 env->Global()->Set(v8_str("fun_instance"), fun_instance);
232 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
234 "var accessor_sig_key = 'accessor_sig';"
235 "var accessor_key = 'accessor';"
236 "var prop_sig_key = 'prop_sig';"
237 "var prop_key = 'prop';"
239 "function copy_props(obj) {"
240 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
241 " var source = Fun.prototype;"
242 " for (var i in keys) {"
243 " var key = keys[i];"
244 " var desc = Object.getOwnPropertyDescriptor(source, key);"
245 " Object.defineProperty(obj, key, desc);"
251 "var unrel = new UnrelFun();"
252 "copy_props(unrel);");
253 // Test with and without ICs
254 const char* test_objects[] = {
255 "fun_instance", "sub_fun_instance", "obj", "unrel" };
256 unsigned bad_signature_start_offset = 2;
257 for (unsigned i = 0; i < arraysize(test_objects); i++) {
258 i::ScopedVector<char> source(200);
260 source, "var test_object = %s; test_object", test_objects[i]);
261 Local<Value> test_object = CompileRun(source.start());
262 TestSignature("test_object.prop();", test_object, isolate);
263 TestSignature("test_object.accessor;", test_object, isolate);
264 TestSignature("test_object[accessor_key];", test_object, isolate);
265 TestSignature("test_object.accessor = 1;", test_object, isolate);
266 TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
267 if (i >= bad_signature_start_offset) test_object = Local<Value>();
268 TestSignature("test_object.prop_sig();", test_object, isolate);
269 TestSignature("test_object.accessor_sig;", test_object, isolate);
270 TestSignature("test_object[accessor_sig_key];", test_object, isolate);
271 TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
272 TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
277 THREADED_TEST(HulIgennem) {
279 v8::Isolate* isolate = env->GetIsolate();
280 v8::HandleScope scope(isolate);
281 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
282 Local<String> undef_str = undef->ToString(isolate);
283 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
284 undef_str->WriteUtf8(value);
285 CHECK_EQ(0, strcmp(value, "undefined"));
286 i::DeleteArray(value);
290 THREADED_TEST(Access) {
292 v8::Isolate* isolate = env->GetIsolate();
293 v8::HandleScope scope(isolate);
294 Local<v8::Object> obj = v8::Object::New(isolate);
295 Local<Value> foo_before = obj->Get(v8_str("foo"));
296 CHECK(foo_before->IsUndefined());
297 Local<String> bar_str = v8_str("bar");
298 obj->Set(v8_str("foo"), bar_str);
299 Local<Value> foo_after = obj->Get(v8_str("foo"));
300 CHECK(!foo_after->IsUndefined());
301 CHECK(foo_after->IsString());
302 CHECK(bar_str->Equals(foo_after));
306 THREADED_TEST(AccessElement) {
308 v8::HandleScope scope(env->GetIsolate());
309 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
310 Local<Value> before = obj->Get(1);
311 CHECK(before->IsUndefined());
312 Local<String> bar_str = v8_str("bar");
313 obj->Set(1, bar_str);
314 Local<Value> after = obj->Get(1);
315 CHECK(!after->IsUndefined());
316 CHECK(after->IsString());
317 CHECK(bar_str->Equals(after));
319 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
320 CHECK(v8_str("a")->Equals(value->Get(0)));
321 CHECK(v8_str("b")->Equals(value->Get(1)));
325 THREADED_TEST(Script) {
327 v8::HandleScope scope(env->GetIsolate());
328 const char* source = "1 + 2 + 3";
329 Local<Script> script = v8_compile(source);
330 CHECK_EQ(6, script->Run()->Int32Value());
334 class TestResource: public String::ExternalStringResource {
336 explicit TestResource(uint16_t* data, int* counter = NULL,
337 bool owning_data = true)
338 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
339 while (data[length_]) ++length_;
343 if (owning_data_) i::DeleteArray(data_);
344 if (counter_ != NULL) ++*counter_;
347 const uint16_t* data() const {
351 size_t length() const {
363 class TestOneByteResource : public String::ExternalOneByteStringResource {
365 explicit TestOneByteResource(const char* data, int* counter = NULL,
368 data_(data + offset),
369 length_(strlen(data) - offset),
372 ~TestOneByteResource() {
373 i::DeleteArray(orig_data_);
374 if (counter_ != NULL) ++*counter_;
377 const char* data() const {
381 size_t length() const {
386 const char* orig_data_;
393 THREADED_TEST(ScriptUsingStringResource) {
394 int dispose_count = 0;
395 const char* c_source = "1 + 2 * 3";
396 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
399 v8::HandleScope scope(env->GetIsolate());
400 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
401 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
402 Local<Script> script = v8_compile(source);
403 Local<Value> value = script->Run();
404 CHECK(value->IsNumber());
405 CHECK_EQ(7, value->Int32Value());
406 CHECK(source->IsExternal());
408 static_cast<TestResource*>(source->GetExternalStringResource()));
409 String::Encoding encoding = String::UNKNOWN_ENCODING;
410 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
411 source->GetExternalStringResourceBase(&encoding));
412 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
413 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
414 CHECK_EQ(0, dispose_count);
416 CcTest::i_isolate()->compilation_cache()->Clear();
417 CcTest::heap()->CollectAllAvailableGarbage();
418 CHECK_EQ(1, dispose_count);
422 THREADED_TEST(ScriptUsingOneByteStringResource) {
423 int dispose_count = 0;
424 const char* c_source = "1 + 2 * 3";
427 v8::HandleScope scope(env->GetIsolate());
428 TestOneByteResource* resource =
429 new TestOneByteResource(i::StrDup(c_source), &dispose_count);
430 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
431 CHECK(source->IsExternalOneByte());
432 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
433 source->GetExternalOneByteStringResource());
434 String::Encoding encoding = String::UNKNOWN_ENCODING;
435 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
436 source->GetExternalStringResourceBase(&encoding));
437 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
438 Local<Script> script = v8_compile(source);
439 Local<Value> value = script->Run();
440 CHECK(value->IsNumber());
441 CHECK_EQ(7, value->Int32Value());
442 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
443 CHECK_EQ(0, dispose_count);
445 CcTest::i_isolate()->compilation_cache()->Clear();
446 CcTest::heap()->CollectAllAvailableGarbage();
447 CHECK_EQ(1, dispose_count);
451 THREADED_TEST(ScriptMakingExternalString) {
452 int dispose_count = 0;
453 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
456 v8::HandleScope scope(env->GetIsolate());
457 Local<String> source =
458 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
459 // Trigger GCs so that the newly allocated string moves to old gen.
460 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
461 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
462 CHECK_EQ(source->IsExternal(), false);
463 CHECK_EQ(source->IsExternalOneByte(), false);
464 String::Encoding encoding = String::UNKNOWN_ENCODING;
465 CHECK(!source->GetExternalStringResourceBase(&encoding));
466 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
467 bool success = source->MakeExternal(new TestResource(two_byte_source,
470 Local<Script> script = v8_compile(source);
471 Local<Value> value = script->Run();
472 CHECK(value->IsNumber());
473 CHECK_EQ(7, value->Int32Value());
474 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
475 CHECK_EQ(0, dispose_count);
477 CcTest::i_isolate()->compilation_cache()->Clear();
478 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
479 CHECK_EQ(1, dispose_count);
483 THREADED_TEST(ScriptMakingExternalOneByteString) {
484 int dispose_count = 0;
485 const char* c_source = "1 + 2 * 3";
488 v8::HandleScope scope(env->GetIsolate());
489 Local<String> source = v8_str(c_source);
490 // Trigger GCs so that the newly allocated string moves to old gen.
491 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
492 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
493 bool success = source->MakeExternal(
494 new TestOneByteResource(i::StrDup(c_source), &dispose_count));
496 Local<Script> script = v8_compile(source);
497 Local<Value> value = script->Run();
498 CHECK(value->IsNumber());
499 CHECK_EQ(7, value->Int32Value());
500 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
501 CHECK_EQ(0, dispose_count);
503 CcTest::i_isolate()->compilation_cache()->Clear();
504 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
505 CHECK_EQ(1, dispose_count);
509 TEST(MakingExternalStringConditions) {
511 v8::HandleScope scope(env->GetIsolate());
513 // Free some space in the new space so that we can check freshness.
514 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
515 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
517 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
518 Local<String> small_string =
519 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
520 i::DeleteArray(two_byte_string);
522 // We should refuse to externalize newly created small string.
523 CHECK(!small_string->CanMakeExternal());
524 // Trigger GCs so that the newly allocated string moves to old gen.
525 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
526 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
527 // Old space strings should be accepted.
528 CHECK(small_string->CanMakeExternal());
530 two_byte_string = AsciiToTwoByteString("small string 2");
531 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
532 i::DeleteArray(two_byte_string);
534 // We should refuse externalizing newly created small string.
535 CHECK(!small_string->CanMakeExternal());
536 for (int i = 0; i < 100; i++) {
537 String::Value value(small_string);
539 // Frequently used strings should be accepted.
540 CHECK(small_string->CanMakeExternal());
542 const int buf_size = 10 * 1024;
543 char* buf = i::NewArray<char>(buf_size);
544 memset(buf, 'a', buf_size);
545 buf[buf_size - 1] = '\0';
547 two_byte_string = AsciiToTwoByteString(buf);
548 Local<String> large_string =
549 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
551 i::DeleteArray(two_byte_string);
552 // Large strings should be immediately accepted.
553 CHECK(large_string->CanMakeExternal());
557 TEST(MakingExternalOneByteStringConditions) {
559 v8::HandleScope scope(env->GetIsolate());
561 // Free some space in the new space so that we can check freshness.
562 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
563 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
565 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
566 // We should refuse to externalize newly created small string.
567 CHECK(!small_string->CanMakeExternal());
568 // Trigger GCs so that the newly allocated string moves to old gen.
569 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
570 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
571 // Old space strings should be accepted.
572 CHECK(small_string->CanMakeExternal());
574 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
575 // We should refuse externalizing newly created small string.
576 CHECK(!small_string->CanMakeExternal());
577 for (int i = 0; i < 100; i++) {
578 String::Value value(small_string);
580 // Frequently used strings should be accepted.
581 CHECK(small_string->CanMakeExternal());
583 const int buf_size = 10 * 1024;
584 char* buf = i::NewArray<char>(buf_size);
585 memset(buf, 'a', buf_size);
586 buf[buf_size - 1] = '\0';
587 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
589 // Large strings should be immediately accepted.
590 CHECK(large_string->CanMakeExternal());
594 TEST(MakingExternalUnalignedOneByteString) {
596 v8::HandleScope scope(env->GetIsolate());
598 CompileRun("function cons(a, b) { return a + b; }"
599 "function slice(a) { return a.substring(1); }");
600 // Create a cons string that will land in old pointer space.
601 Local<String> cons = Local<String>::Cast(CompileRun(
602 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
603 // Create a sliced string that will land in old pointer space.
604 Local<String> slice = Local<String>::Cast(CompileRun(
605 "slice('abcdefghijklmnopqrstuvwxyz');"));
607 // Trigger GCs so that the newly allocated string moves to old gen.
608 SimulateFullSpace(CcTest::heap()->old_pointer_space());
609 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
610 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
612 // Turn into external string with unaligned resource data.
613 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
615 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
617 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
619 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
622 // Trigger GCs and force evacuation.
623 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
624 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
628 THREADED_TEST(UsingExternalString) {
629 i::Factory* factory = CcTest::i_isolate()->factory();
631 v8::HandleScope scope(CcTest::isolate());
632 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
633 Local<String> string = String::NewExternal(
634 CcTest::isolate(), new TestResource(two_byte_string));
635 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
636 // Trigger GCs so that the newly allocated string moves to old gen.
637 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
638 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
639 i::Handle<i::String> isymbol =
640 factory->InternalizeString(istring);
641 CHECK(isymbol->IsInternalizedString());
643 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
644 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
648 THREADED_TEST(UsingExternalOneByteString) {
649 i::Factory* factory = CcTest::i_isolate()->factory();
651 v8::HandleScope scope(CcTest::isolate());
652 const char* one_byte_string = "test string";
653 Local<String> string = String::NewExternal(
654 CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
655 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
656 // Trigger GCs so that the newly allocated string moves to old gen.
657 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
658 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
659 i::Handle<i::String> isymbol =
660 factory->InternalizeString(istring);
661 CHECK(isymbol->IsInternalizedString());
663 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
664 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
668 class RandomLengthResource : public v8::String::ExternalStringResource {
670 explicit RandomLengthResource(int length) : length_(length) {}
671 virtual const uint16_t* data() const { return string_; }
672 virtual size_t length() const { return length_; }
675 uint16_t string_[10];
680 class RandomLengthOneByteResource
681 : public v8::String::ExternalOneByteStringResource {
683 explicit RandomLengthOneByteResource(int length) : length_(length) {}
684 virtual const char* data() const { return string_; }
685 virtual size_t length() const { return length_; }
693 THREADED_TEST(NewExternalForVeryLongString) {
696 v8::HandleScope scope(env->GetIsolate());
697 v8::TryCatch try_catch;
698 RandomLengthOneByteResource r(1 << 30);
699 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
700 CHECK(str.IsEmpty());
701 CHECK(try_catch.HasCaught());
702 String::Utf8Value exception_value(try_catch.Exception());
703 CHECK_EQ(0, strcmp("RangeError: Invalid string length", *exception_value));
708 v8::HandleScope scope(env->GetIsolate());
709 v8::TryCatch try_catch;
710 RandomLengthResource r(1 << 30);
711 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
712 CHECK(str.IsEmpty());
713 CHECK(try_catch.HasCaught());
714 String::Utf8Value exception_value(try_catch.Exception());
715 CHECK_EQ(0, strcmp("RangeError: Invalid string length", *exception_value));
720 THREADED_TEST(ScavengeExternalString) {
721 i::FLAG_stress_compaction = false;
722 i::FLAG_gc_global = false;
723 int dispose_count = 0;
724 bool in_new_space = false;
726 v8::HandleScope scope(CcTest::isolate());
727 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
728 Local<String> string = String::NewExternal(
729 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
730 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
731 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
732 in_new_space = CcTest::heap()->InNewSpace(*istring);
733 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
734 CHECK_EQ(0, dispose_count);
736 CcTest::heap()->CollectGarbage(
737 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
738 CHECK_EQ(1, dispose_count);
742 THREADED_TEST(ScavengeExternalOneByteString) {
743 i::FLAG_stress_compaction = false;
744 i::FLAG_gc_global = false;
745 int dispose_count = 0;
746 bool in_new_space = false;
748 v8::HandleScope scope(CcTest::isolate());
749 const char* one_byte_string = "test string";
750 Local<String> string = String::NewExternal(
752 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
753 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
754 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
755 in_new_space = CcTest::heap()->InNewSpace(*istring);
756 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
757 CHECK_EQ(0, dispose_count);
759 CcTest::heap()->CollectGarbage(
760 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
761 CHECK_EQ(1, dispose_count);
765 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
767 // Only used by non-threaded tests, so it can use static fields.
768 static int dispose_calls;
769 static int dispose_count;
771 TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
772 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
776 if (dispose_) delete this;
783 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
784 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
787 TEST(ExternalStringWithDisposeHandling) {
788 const char* c_source = "1 + 2 * 3";
790 // Use a stack allocated external string resource allocated object.
791 TestOneByteResourceWithDisposeControl::dispose_count = 0;
792 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
793 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
796 v8::HandleScope scope(env->GetIsolate());
797 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
798 Local<Script> script = v8_compile(source);
799 Local<Value> value = script->Run();
800 CHECK(value->IsNumber());
801 CHECK_EQ(7, value->Int32Value());
802 CcTest::heap()->CollectAllAvailableGarbage();
803 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
805 CcTest::i_isolate()->compilation_cache()->Clear();
806 CcTest::heap()->CollectAllAvailableGarbage();
807 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
808 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
810 // Use a heap allocated external string resource allocated object.
811 TestOneByteResourceWithDisposeControl::dispose_count = 0;
812 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
813 TestOneByteResource* res_heap =
814 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
817 v8::HandleScope scope(env->GetIsolate());
818 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
819 Local<Script> script = v8_compile(source);
820 Local<Value> value = script->Run();
821 CHECK(value->IsNumber());
822 CHECK_EQ(7, value->Int32Value());
823 CcTest::heap()->CollectAllAvailableGarbage();
824 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
826 CcTest::i_isolate()->compilation_cache()->Clear();
827 CcTest::heap()->CollectAllAvailableGarbage();
828 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
829 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
833 THREADED_TEST(StringConcat) {
836 v8::HandleScope scope(env->GetIsolate());
837 const char* one_byte_string_1 = "function a_times_t";
838 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
839 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
840 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
841 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
842 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
843 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
844 Local<String> left = v8_str(one_byte_string_1);
846 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
847 Local<String> right =
848 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
849 i::DeleteArray(two_byte_source);
851 Local<String> source = String::Concat(left, right);
852 right = String::NewExternal(
854 new TestOneByteResource(i::StrDup(one_byte_extern_1)));
855 source = String::Concat(source, right);
856 right = String::NewExternal(
858 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
859 source = String::Concat(source, right);
860 right = v8_str(one_byte_string_2);
861 source = String::Concat(source, right);
863 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
864 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
865 i::DeleteArray(two_byte_source);
867 source = String::Concat(source, right);
868 right = String::NewExternal(
870 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
871 source = String::Concat(source, right);
872 Local<Script> script = v8_compile(source);
873 Local<Value> value = script->Run();
874 CHECK(value->IsNumber());
875 CHECK_EQ(68, value->Int32Value());
877 CcTest::i_isolate()->compilation_cache()->Clear();
878 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
879 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
883 THREADED_TEST(GlobalProperties) {
885 v8::HandleScope scope(env->GetIsolate());
886 v8::Handle<v8::Object> global = env->Global();
887 global->Set(v8_str("pi"), v8_num(3.1415926));
888 Local<Value> pi = global->Get(v8_str("pi"));
889 CHECK_EQ(3.1415926, pi->NumberValue());
893 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
894 i::Address callback) {
895 ApiTestFuzzer::Fuzz();
896 CheckReturnValue(info, callback);
897 info.GetReturnValue().Set(v8_str("bad value"));
898 info.GetReturnValue().Set(v8_num(102));
902 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
903 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
907 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
908 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
911 static void construct_callback(
912 const v8::FunctionCallbackInfo<Value>& info) {
913 ApiTestFuzzer::Fuzz();
914 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
915 info.This()->Set(v8_str("x"), v8_num(1));
916 info.This()->Set(v8_str("y"), v8_num(2));
917 info.GetReturnValue().Set(v8_str("bad value"));
918 info.GetReturnValue().Set(info.This());
922 static void Return239Callback(
923 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
924 ApiTestFuzzer::Fuzz();
925 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
926 info.GetReturnValue().Set(v8_str("bad value"));
927 info.GetReturnValue().Set(v8_num(239));
931 template<typename Handler>
932 static void TestFunctionTemplateInitializer(Handler handler,
934 // Test constructor calls.
937 v8::Isolate* isolate = env->GetIsolate();
938 v8::HandleScope scope(isolate);
940 Local<v8::FunctionTemplate> fun_templ =
941 v8::FunctionTemplate::New(isolate, handler);
942 Local<Function> fun = fun_templ->GetFunction();
943 env->Global()->Set(v8_str("obj"), fun);
944 Local<Script> script = v8_compile("obj()");
945 for (int i = 0; i < 30; i++) {
946 CHECK_EQ(102, script->Run()->Int32Value());
949 // Use SetCallHandler to initialize a function template, should work like
953 v8::Isolate* isolate = env->GetIsolate();
954 v8::HandleScope scope(isolate);
956 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
957 fun_templ->SetCallHandler(handler_2);
958 Local<Function> fun = fun_templ->GetFunction();
959 env->Global()->Set(v8_str("obj"), fun);
960 Local<Script> script = v8_compile("obj()");
961 for (int i = 0; i < 30; i++) {
962 CHECK_EQ(102, script->Run()->Int32Value());
968 template<typename Constructor, typename Accessor>
969 static void TestFunctionTemplateAccessor(Constructor constructor,
972 v8::HandleScope scope(env->GetIsolate());
974 Local<v8::FunctionTemplate> fun_templ =
975 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
976 fun_templ->SetClassName(v8_str("funky"));
977 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
978 Local<Function> fun = fun_templ->GetFunction();
979 env->Global()->Set(v8_str("obj"), fun);
980 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
981 CHECK(v8_str("[object funky]")->Equals(result));
982 CompileRun("var obj_instance = new obj();");
983 Local<Script> script;
984 script = v8_compile("obj_instance.x");
985 for (int i = 0; i < 30; i++) {
986 CHECK_EQ(1, script->Run()->Int32Value());
988 script = v8_compile("obj_instance.m");
989 for (int i = 0; i < 30; i++) {
990 CHECK_EQ(239, script->Run()->Int32Value());
995 THREADED_PROFILED_TEST(FunctionTemplate) {
996 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
997 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1001 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1002 ApiTestFuzzer::Fuzz();
1003 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1004 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1008 template<typename Callback>
1009 static void TestSimpleCallback(Callback callback) {
1011 v8::Isolate* isolate = env->GetIsolate();
1012 v8::HandleScope scope(isolate);
1014 v8::Handle<v8::ObjectTemplate> object_template =
1015 v8::ObjectTemplate::New(isolate);
1016 object_template->Set(isolate, "callback",
1017 v8::FunctionTemplate::New(isolate, callback));
1018 v8::Local<v8::Object> object = object_template->NewInstance();
1019 (*env)->Global()->Set(v8_str("callback_object"), object);
1020 v8::Handle<v8::Script> script;
1021 script = v8_compile("callback_object.callback(17)");
1022 for (int i = 0; i < 30; i++) {
1023 CHECK_EQ(51424, script->Run()->Int32Value());
1025 script = v8_compile("callback_object.callback(17, 24)");
1026 for (int i = 0; i < 30; i++) {
1027 CHECK_EQ(51425, script->Run()->Int32Value());
1032 THREADED_PROFILED_TEST(SimpleCallback) {
1033 TestSimpleCallback(SimpleCallback);
1037 template<typename T>
1038 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1040 // constant return values
1041 static int32_t fast_return_value_int32 = 471;
1042 static uint32_t fast_return_value_uint32 = 571;
1043 static const double kFastReturnValueDouble = 2.7;
1044 // variable return values
1045 static bool fast_return_value_bool = false;
1046 enum ReturnValueOddball {
1048 kUndefinedReturnValue,
1049 kEmptyStringReturnValue
1051 static ReturnValueOddball fast_return_value_void;
1052 static bool fast_return_value_object_is_empty = false;
1054 // Helper function to avoid compiler error: insufficient contextual information
1055 // to determine type when applying FUNCTION_ADDR to a template function.
1056 static i::Address address_of(v8::FunctionCallback callback) {
1057 return FUNCTION_ADDR(callback);
1061 void FastReturnValueCallback<int32_t>(
1062 const v8::FunctionCallbackInfo<v8::Value>& info) {
1063 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1064 info.GetReturnValue().Set(fast_return_value_int32);
1068 void FastReturnValueCallback<uint32_t>(
1069 const v8::FunctionCallbackInfo<v8::Value>& info) {
1070 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1071 info.GetReturnValue().Set(fast_return_value_uint32);
1075 void FastReturnValueCallback<double>(
1076 const v8::FunctionCallbackInfo<v8::Value>& info) {
1077 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1078 info.GetReturnValue().Set(kFastReturnValueDouble);
1082 void FastReturnValueCallback<bool>(
1083 const v8::FunctionCallbackInfo<v8::Value>& info) {
1084 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1085 info.GetReturnValue().Set(fast_return_value_bool);
1089 void FastReturnValueCallback<void>(
1090 const v8::FunctionCallbackInfo<v8::Value>& info) {
1091 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1092 switch (fast_return_value_void) {
1093 case kNullReturnValue:
1094 info.GetReturnValue().SetNull();
1096 case kUndefinedReturnValue:
1097 info.GetReturnValue().SetUndefined();
1099 case kEmptyStringReturnValue:
1100 info.GetReturnValue().SetEmptyString();
1106 void FastReturnValueCallback<Object>(
1107 const v8::FunctionCallbackInfo<v8::Value>& info) {
1108 v8::Handle<v8::Object> object;
1109 if (!fast_return_value_object_is_empty) {
1110 object = Object::New(info.GetIsolate());
1112 info.GetReturnValue().Set(object);
1115 template<typename T>
1116 Handle<Value> TestFastReturnValues() {
1118 v8::Isolate* isolate = env->GetIsolate();
1119 v8::EscapableHandleScope scope(isolate);
1120 v8::Handle<v8::ObjectTemplate> object_template =
1121 v8::ObjectTemplate::New(isolate);
1122 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1123 object_template->Set(isolate, "callback",
1124 v8::FunctionTemplate::New(isolate, callback));
1125 v8::Local<v8::Object> object = object_template->NewInstance();
1126 (*env)->Global()->Set(v8_str("callback_object"), object);
1127 return scope.Escape(CompileRun("callback_object.callback()"));
1131 THREADED_PROFILED_TEST(FastReturnValues) {
1133 v8::Isolate* isolate = env->GetIsolate();
1134 v8::HandleScope scope(isolate);
1135 v8::Handle<v8::Value> value;
1136 // check int32_t and uint32_t
1137 int32_t int_values[] = {
1139 i::Smi::kMinValue, i::Smi::kMaxValue
1141 for (size_t i = 0; i < arraysize(int_values); i++) {
1142 for (int modifier = -1; modifier <= 1; modifier++) {
1143 int int_value = int_values[i] + modifier;
1145 fast_return_value_int32 = int_value;
1146 value = TestFastReturnValues<int32_t>();
1147 CHECK(value->IsInt32());
1148 CHECK(fast_return_value_int32 == value->Int32Value());
1150 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1151 value = TestFastReturnValues<uint32_t>();
1152 CHECK(value->IsUint32());
1153 CHECK(fast_return_value_uint32 == value->Uint32Value());
1157 value = TestFastReturnValues<double>();
1158 CHECK(value->IsNumber());
1159 CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
1160 // check bool values
1161 for (int i = 0; i < 2; i++) {
1162 fast_return_value_bool = i == 0;
1163 value = TestFastReturnValues<bool>();
1164 CHECK(value->IsBoolean());
1165 CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
1168 ReturnValueOddball oddballs[] = {
1170 kUndefinedReturnValue,
1171 kEmptyStringReturnValue
1173 for (size_t i = 0; i < arraysize(oddballs); i++) {
1174 fast_return_value_void = oddballs[i];
1175 value = TestFastReturnValues<void>();
1176 switch (fast_return_value_void) {
1177 case kNullReturnValue:
1178 CHECK(value->IsNull());
1180 case kUndefinedReturnValue:
1181 CHECK(value->IsUndefined());
1183 case kEmptyStringReturnValue:
1184 CHECK(value->IsString());
1185 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1190 fast_return_value_object_is_empty = false;
1191 value = TestFastReturnValues<Object>();
1192 CHECK(value->IsObject());
1193 fast_return_value_object_is_empty = true;
1194 value = TestFastReturnValues<Object>();
1195 CHECK(value->IsUndefined());
1199 THREADED_TEST(FunctionTemplateSetLength) {
1201 v8::Isolate* isolate = env->GetIsolate();
1202 v8::HandleScope scope(isolate);
1204 Local<v8::FunctionTemplate> fun_templ =
1205 v8::FunctionTemplate::New(isolate,
1207 Handle<v8::Value>(),
1208 Handle<v8::Signature>(),
1210 Local<Function> fun = fun_templ->GetFunction();
1211 env->Global()->Set(v8_str("obj"), fun);
1212 Local<Script> script = v8_compile("obj.length");
1213 CHECK_EQ(23, script->Run()->Int32Value());
1216 Local<v8::FunctionTemplate> fun_templ =
1217 v8::FunctionTemplate::New(isolate, handle_callback);
1218 fun_templ->SetLength(22);
1219 Local<Function> fun = fun_templ->GetFunction();
1220 env->Global()->Set(v8_str("obj"), fun);
1221 Local<Script> script = v8_compile("obj.length");
1222 CHECK_EQ(22, script->Run()->Int32Value());
1225 // Without setting length it defaults to 0.
1226 Local<v8::FunctionTemplate> fun_templ =
1227 v8::FunctionTemplate::New(isolate, handle_callback);
1228 Local<Function> fun = fun_templ->GetFunction();
1229 env->Global()->Set(v8_str("obj"), fun);
1230 Local<Script> script = v8_compile("obj.length");
1231 CHECK_EQ(0, script->Run()->Int32Value());
1236 static void* expected_ptr;
1237 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1238 void* ptr = v8::External::Cast(*args.Data())->Value();
1239 CHECK_EQ(expected_ptr, ptr);
1240 args.GetReturnValue().Set(true);
1244 static void TestExternalPointerWrapping() {
1246 v8::Isolate* isolate = env->GetIsolate();
1247 v8::HandleScope scope(isolate);
1249 v8::Handle<v8::Value> data =
1250 v8::External::New(isolate, expected_ptr);
1252 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1253 obj->Set(v8_str("func"),
1254 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1255 env->Global()->Set(v8_str("obj"), obj);
1258 "function foo() {\n"
1259 " for (var i = 0; i < 13; i++) obj.func();\n"
1261 "foo(), true")->BooleanValue());
1265 THREADED_TEST(ExternalWrap) {
1266 // Check heap allocated object.
1269 TestExternalPointerWrapping();
1272 // Check stack allocated object.
1274 expected_ptr = &foo;
1275 TestExternalPointerWrapping();
1277 // Check not aligned addresses.
1279 char* s = new char[n];
1280 for (int i = 0; i < n; i++) {
1281 expected_ptr = s + i;
1282 TestExternalPointerWrapping();
1287 // Check several invalid addresses.
1288 expected_ptr = reinterpret_cast<void*>(1);
1289 TestExternalPointerWrapping();
1291 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1292 TestExternalPointerWrapping();
1294 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1295 TestExternalPointerWrapping();
1297 #if defined(V8_HOST_ARCH_X64)
1298 // Check a value with a leading 1 bit in x64 Smi encoding.
1299 expected_ptr = reinterpret_cast<void*>(0x400000000);
1300 TestExternalPointerWrapping();
1302 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1303 TestExternalPointerWrapping();
1305 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1306 TestExternalPointerWrapping();
1311 THREADED_TEST(FindInstanceInPrototypeChain) {
1313 v8::Isolate* isolate = env->GetIsolate();
1314 v8::HandleScope scope(isolate);
1316 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1317 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1318 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1319 derived->Inherit(base);
1321 Local<v8::Function> base_function = base->GetFunction();
1322 Local<v8::Function> derived_function = derived->GetFunction();
1323 Local<v8::Function> other_function = other->GetFunction();
1325 Local<v8::Object> base_instance = base_function->NewInstance();
1326 Local<v8::Object> derived_instance = derived_function->NewInstance();
1327 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1328 Local<v8::Object> other_instance = other_function->NewInstance();
1329 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1330 other_instance->Set(v8_str("__proto__"), derived_instance2);
1332 // base_instance is only an instance of base.
1334 base_instance->Equals(base_instance->FindInstanceInPrototypeChain(base)));
1335 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1336 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1338 // derived_instance is an instance of base and derived.
1339 CHECK(derived_instance->Equals(
1340 derived_instance->FindInstanceInPrototypeChain(base)));
1341 CHECK(derived_instance->Equals(
1342 derived_instance->FindInstanceInPrototypeChain(derived)));
1343 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1345 // other_instance is an instance of other and its immediate
1346 // prototype derived_instance2 is an instance of base and derived.
1347 // Note, derived_instance is an instance of base and derived too,
1348 // but it comes after derived_instance2 in the prototype chain of
1350 CHECK(derived_instance2->Equals(
1351 other_instance->FindInstanceInPrototypeChain(base)));
1352 CHECK(derived_instance2->Equals(
1353 other_instance->FindInstanceInPrototypeChain(derived)));
1354 CHECK(other_instance->Equals(
1355 other_instance->FindInstanceInPrototypeChain(other)));
1359 THREADED_TEST(TinyInteger) {
1361 v8::Isolate* isolate = env->GetIsolate();
1362 v8::HandleScope scope(isolate);
1364 int32_t value = 239;
1365 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1366 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1368 value_obj = v8::Integer::New(isolate, value);
1369 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1373 THREADED_TEST(BigSmiInteger) {
1375 v8::HandleScope scope(env->GetIsolate());
1376 v8::Isolate* isolate = CcTest::isolate();
1378 int32_t value = i::Smi::kMaxValue;
1379 // We cannot add one to a Smi::kMaxValue without wrapping.
1380 if (i::SmiValuesAre31Bits()) {
1381 CHECK(i::Smi::IsValid(value));
1382 CHECK(!i::Smi::IsValid(value + 1));
1384 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1385 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1387 value_obj = v8::Integer::New(isolate, value);
1388 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1393 THREADED_TEST(BigInteger) {
1395 v8::HandleScope scope(env->GetIsolate());
1396 v8::Isolate* isolate = CcTest::isolate();
1398 // We cannot add one to a Smi::kMaxValue without wrapping.
1399 if (i::SmiValuesAre31Bits()) {
1400 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1401 // The code will not be run in that case, due to the "if" guard.
1403 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1404 CHECK(value > i::Smi::kMaxValue);
1405 CHECK(!i::Smi::IsValid(value));
1407 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1408 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1410 value_obj = v8::Integer::New(isolate, value);
1411 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1416 THREADED_TEST(TinyUnsignedInteger) {
1418 v8::HandleScope scope(env->GetIsolate());
1419 v8::Isolate* isolate = CcTest::isolate();
1421 uint32_t value = 239;
1423 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1424 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1426 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1427 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1431 THREADED_TEST(BigUnsignedSmiInteger) {
1433 v8::HandleScope scope(env->GetIsolate());
1434 v8::Isolate* isolate = CcTest::isolate();
1436 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1437 CHECK(i::Smi::IsValid(value));
1438 CHECK(!i::Smi::IsValid(value + 1));
1440 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1441 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1443 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1444 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1448 THREADED_TEST(BigUnsignedInteger) {
1450 v8::HandleScope scope(env->GetIsolate());
1451 v8::Isolate* isolate = CcTest::isolate();
1453 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1454 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1455 CHECK(!i::Smi::IsValid(value));
1457 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1458 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1460 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1461 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1465 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1467 v8::HandleScope scope(env->GetIsolate());
1468 v8::Isolate* isolate = CcTest::isolate();
1470 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1471 uint32_t value = INT32_MAX_AS_UINT + 1;
1472 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1474 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1475 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1477 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1478 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1482 THREADED_TEST(IsNativeError) {
1484 v8::HandleScope scope(env->GetIsolate());
1485 v8::Handle<Value> syntax_error = CompileRun(
1486 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1487 CHECK(syntax_error->IsNativeError());
1488 v8::Handle<Value> not_error = CompileRun("{a:42}");
1489 CHECK(!not_error->IsNativeError());
1490 v8::Handle<Value> not_object = CompileRun("42");
1491 CHECK(!not_object->IsNativeError());
1495 THREADED_TEST(IsGeneratorFunctionOrObject) {
1497 v8::HandleScope scope(env->GetIsolate());
1499 CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1500 v8::Handle<Value> gen = CompileRun("gen");
1501 v8::Handle<Value> genObj = CompileRun("gen()");
1502 v8::Handle<Value> object = CompileRun("{a:42}");
1503 v8::Handle<Value> func = CompileRun("func");
1505 CHECK(gen->IsGeneratorFunction());
1506 CHECK(gen->IsFunction());
1507 CHECK(!gen->IsGeneratorObject());
1509 CHECK(!genObj->IsGeneratorFunction());
1510 CHECK(!genObj->IsFunction());
1511 CHECK(genObj->IsGeneratorObject());
1513 CHECK(!object->IsGeneratorFunction());
1514 CHECK(!object->IsFunction());
1515 CHECK(!object->IsGeneratorObject());
1517 CHECK(!func->IsGeneratorFunction());
1518 CHECK(func->IsFunction());
1519 CHECK(!func->IsGeneratorObject());
1523 THREADED_TEST(ArgumentsObject) {
1525 v8::HandleScope scope(env->GetIsolate());
1526 v8::Handle<Value> arguments_object =
1527 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1528 CHECK(arguments_object->IsArgumentsObject());
1529 v8::Handle<Value> array = CompileRun("[1,2,3]");
1530 CHECK(!array->IsArgumentsObject());
1531 v8::Handle<Value> object = CompileRun("{a:42}");
1532 CHECK(!object->IsArgumentsObject());
1536 THREADED_TEST(IsMapOrSet) {
1538 v8::HandleScope scope(env->GetIsolate());
1539 v8::Handle<Value> map = CompileRun("new Map()");
1540 v8::Handle<Value> set = CompileRun("new Set()");
1541 v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1542 v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1543 CHECK(map->IsMap());
1544 CHECK(set->IsSet());
1545 CHECK(weak_map->IsWeakMap());
1546 CHECK(weak_set->IsWeakSet());
1548 CHECK(!map->IsSet());
1549 CHECK(!map->IsWeakMap());
1550 CHECK(!map->IsWeakSet());
1552 CHECK(!set->IsMap());
1553 CHECK(!set->IsWeakMap());
1554 CHECK(!set->IsWeakSet());
1556 CHECK(!weak_map->IsMap());
1557 CHECK(!weak_map->IsSet());
1558 CHECK(!weak_map->IsWeakSet());
1560 CHECK(!weak_set->IsMap());
1561 CHECK(!weak_set->IsSet());
1562 CHECK(!weak_set->IsWeakMap());
1564 v8::Handle<Value> object = CompileRun("{a:42}");
1565 CHECK(!object->IsMap());
1566 CHECK(!object->IsSet());
1567 CHECK(!object->IsWeakMap());
1568 CHECK(!object->IsWeakSet());
1572 THREADED_TEST(StringObject) {
1574 v8::HandleScope scope(env->GetIsolate());
1575 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1576 CHECK(boxed_string->IsStringObject());
1577 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1578 CHECK(!unboxed_string->IsStringObject());
1579 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1580 CHECK(!boxed_not_string->IsStringObject());
1581 v8::Handle<Value> not_object = CompileRun("0");
1582 CHECK(!not_object->IsStringObject());
1583 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1584 CHECK(!as_boxed.IsEmpty());
1585 Local<v8::String> the_string = as_boxed->ValueOf();
1586 CHECK(!the_string.IsEmpty());
1587 ExpectObject("\"test\"", the_string);
1588 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1589 CHECK(new_boxed_string->IsStringObject());
1590 as_boxed = new_boxed_string.As<v8::StringObject>();
1591 the_string = as_boxed->ValueOf();
1592 CHECK(!the_string.IsEmpty());
1593 ExpectObject("\"test\"", the_string);
1597 THREADED_TEST(NumberObject) {
1599 v8::HandleScope scope(env->GetIsolate());
1600 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1601 CHECK(boxed_number->IsNumberObject());
1602 v8::Handle<Value> unboxed_number = CompileRun("42");
1603 CHECK(!unboxed_number->IsNumberObject());
1604 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1605 CHECK(!boxed_not_number->IsNumberObject());
1606 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1607 CHECK(!as_boxed.IsEmpty());
1608 double the_number = as_boxed->ValueOf();
1609 CHECK_EQ(42.0, the_number);
1610 v8::Handle<v8::Value> new_boxed_number =
1611 v8::NumberObject::New(env->GetIsolate(), 43);
1612 CHECK(new_boxed_number->IsNumberObject());
1613 as_boxed = new_boxed_number.As<v8::NumberObject>();
1614 the_number = as_boxed->ValueOf();
1615 CHECK_EQ(43.0, the_number);
1619 THREADED_TEST(BooleanObject) {
1621 v8::HandleScope scope(env->GetIsolate());
1622 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1623 CHECK(boxed_boolean->IsBooleanObject());
1624 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1625 CHECK(!unboxed_boolean->IsBooleanObject());
1626 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1627 CHECK(!boxed_not_boolean->IsBooleanObject());
1628 v8::Handle<v8::BooleanObject> as_boxed =
1629 boxed_boolean.As<v8::BooleanObject>();
1630 CHECK(!as_boxed.IsEmpty());
1631 bool the_boolean = as_boxed->ValueOf();
1632 CHECK_EQ(true, the_boolean);
1633 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1634 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1635 CHECK(boxed_true->IsBooleanObject());
1636 CHECK(boxed_false->IsBooleanObject());
1637 as_boxed = boxed_true.As<v8::BooleanObject>();
1638 CHECK_EQ(true, as_boxed->ValueOf());
1639 as_boxed = boxed_false.As<v8::BooleanObject>();
1640 CHECK_EQ(false, as_boxed->ValueOf());
1644 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1646 v8::HandleScope scope(env->GetIsolate());
1648 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1649 CHECK(primitive_false->IsBoolean());
1650 CHECK(!primitive_false->IsBooleanObject());
1651 CHECK(!primitive_false->BooleanValue());
1652 CHECK(!primitive_false->IsTrue());
1653 CHECK(primitive_false->IsFalse());
1655 Local<Value> false_value = BooleanObject::New(false);
1656 CHECK(!false_value->IsBoolean());
1657 CHECK(false_value->IsBooleanObject());
1658 CHECK(false_value->BooleanValue());
1659 CHECK(!false_value->IsTrue());
1660 CHECK(!false_value->IsFalse());
1662 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1663 CHECK(!false_boolean_object->IsBoolean());
1664 CHECK(false_boolean_object->IsBooleanObject());
1665 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1666 // CHECK(false_boolean_object->BooleanValue());
1667 CHECK(!false_boolean_object->ValueOf());
1668 CHECK(!false_boolean_object->IsTrue());
1669 CHECK(!false_boolean_object->IsFalse());
1671 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1672 CHECK(primitive_true->IsBoolean());
1673 CHECK(!primitive_true->IsBooleanObject());
1674 CHECK(primitive_true->BooleanValue());
1675 CHECK(primitive_true->IsTrue());
1676 CHECK(!primitive_true->IsFalse());
1678 Local<Value> true_value = BooleanObject::New(true);
1679 CHECK(!true_value->IsBoolean());
1680 CHECK(true_value->IsBooleanObject());
1681 CHECK(true_value->BooleanValue());
1682 CHECK(!true_value->IsTrue());
1683 CHECK(!true_value->IsFalse());
1685 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1686 CHECK(!true_boolean_object->IsBoolean());
1687 CHECK(true_boolean_object->IsBooleanObject());
1688 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1689 // CHECK(true_boolean_object->BooleanValue());
1690 CHECK(true_boolean_object->ValueOf());
1691 CHECK(!true_boolean_object->IsTrue());
1692 CHECK(!true_boolean_object->IsFalse());
1696 THREADED_TEST(Number) {
1698 v8::HandleScope scope(env->GetIsolate());
1699 double PI = 3.1415926;
1700 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1701 CHECK_EQ(PI, pi_obj->NumberValue());
1705 THREADED_TEST(ToNumber) {
1707 v8::Isolate* isolate = CcTest::isolate();
1708 v8::HandleScope scope(isolate);
1709 Local<String> str = v8_str("3.1415926");
1710 CHECK_EQ(3.1415926, str->NumberValue());
1711 v8::Handle<v8::Boolean> t = v8::True(isolate);
1712 CHECK_EQ(1.0, t->NumberValue());
1713 v8::Handle<v8::Boolean> f = v8::False(isolate);
1714 CHECK_EQ(0.0, f->NumberValue());
1718 THREADED_TEST(Date) {
1720 v8::HandleScope scope(env->GetIsolate());
1721 double PI = 3.1415926;
1722 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1723 CHECK_EQ(3.0, date->NumberValue());
1724 date.As<v8::Date>()->Set(v8_str("property"),
1725 v8::Integer::New(env->GetIsolate(), 42));
1726 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1730 THREADED_TEST(Boolean) {
1732 v8::Isolate* isolate = env->GetIsolate();
1733 v8::HandleScope scope(isolate);
1734 v8::Handle<v8::Boolean> t = v8::True(isolate);
1736 v8::Handle<v8::Boolean> f = v8::False(isolate);
1738 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1739 CHECK(!u->BooleanValue());
1740 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1741 CHECK(!n->BooleanValue());
1742 v8::Handle<String> str1 = v8_str("");
1743 CHECK(!str1->BooleanValue());
1744 v8::Handle<String> str2 = v8_str("x");
1745 CHECK(str2->BooleanValue());
1746 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1747 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1748 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1749 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1750 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1754 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1755 ApiTestFuzzer::Fuzz();
1756 args.GetReturnValue().Set(v8_num(13.4));
1760 static void GetM(Local<String> name,
1761 const v8::PropertyCallbackInfo<v8::Value>& info) {
1762 ApiTestFuzzer::Fuzz();
1763 info.GetReturnValue().Set(v8_num(876));
1767 THREADED_TEST(GlobalPrototype) {
1768 v8::Isolate* isolate = CcTest::isolate();
1769 v8::HandleScope scope(isolate);
1770 v8::Handle<v8::FunctionTemplate> func_templ =
1771 v8::FunctionTemplate::New(isolate);
1772 func_templ->PrototypeTemplate()->Set(
1773 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1774 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1775 templ->Set(isolate, "x", v8_num(200));
1776 templ->SetAccessor(v8_str("m"), GetM);
1777 LocalContext env(0, templ);
1778 v8::Handle<Script> script(v8_compile("dummy()"));
1779 v8::Handle<Value> result(script->Run());
1780 CHECK_EQ(13.4, result->NumberValue());
1781 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1782 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1786 THREADED_TEST(ObjectTemplate) {
1787 v8::Isolate* isolate = CcTest::isolate();
1788 v8::HandleScope scope(isolate);
1789 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1790 templ1->Set(isolate, "x", v8_num(10));
1791 templ1->Set(isolate, "y", v8_num(13));
1793 Local<v8::Object> instance1 = templ1->NewInstance();
1794 env->Global()->Set(v8_str("p"), instance1);
1795 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1796 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1797 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1798 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1799 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1800 templ2->Set(isolate, "a", v8_num(12));
1801 templ2->Set(isolate, "b", templ1);
1802 Local<v8::Object> instance2 = templ2->NewInstance();
1803 env->Global()->Set(v8_str("q"), instance2);
1804 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1805 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1806 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1807 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1811 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1812 ApiTestFuzzer::Fuzz();
1813 args.GetReturnValue().Set(v8_num(17.2));
1817 static void GetKnurd(Local<String> property,
1818 const v8::PropertyCallbackInfo<v8::Value>& info) {
1819 ApiTestFuzzer::Fuzz();
1820 info.GetReturnValue().Set(v8_num(15.2));
1824 THREADED_TEST(DescriptorInheritance) {
1825 v8::Isolate* isolate = CcTest::isolate();
1826 v8::HandleScope scope(isolate);
1827 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1828 super->PrototypeTemplate()->Set(isolate, "flabby",
1829 v8::FunctionTemplate::New(isolate,
1831 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1833 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1835 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1836 base1->Inherit(super);
1837 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1839 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1840 base2->Inherit(super);
1841 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1845 env->Global()->Set(v8_str("s"), super->GetFunction());
1846 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1847 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1849 // Checks right __proto__ chain.
1850 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1851 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1853 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1855 // Instance accessor should not be visible on function object or its prototype
1856 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1857 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1858 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1860 env->Global()->Set(v8_str("obj"),
1861 base1->GetFunction()->NewInstance());
1862 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1863 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1864 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1865 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1866 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1868 env->Global()->Set(v8_str("obj2"),
1869 base2->GetFunction()->NewInstance());
1870 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1871 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1872 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1873 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1874 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1876 // base1 and base2 cannot cross reference to each's prototype
1877 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1878 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1882 // Helper functions for Interceptor/Accessor interaction tests
1884 void SimpleAccessorGetter(Local<String> name,
1885 const v8::PropertyCallbackInfo<v8::Value>& info) {
1886 Handle<Object> self = Handle<Object>::Cast(info.This());
1887 info.GetReturnValue().Set(
1888 self->Get(String::Concat(v8_str("accessor_"), name)));
1891 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
1892 const v8::PropertyCallbackInfo<void>& info) {
1893 Handle<Object> self = Handle<Object>::Cast(info.This());
1894 self->Set(String::Concat(v8_str("accessor_"), name), value);
1897 void SymbolAccessorGetter(Local<Name> name,
1898 const v8::PropertyCallbackInfo<v8::Value>& info) {
1899 CHECK(name->IsSymbol());
1900 Local<Symbol> sym = Local<Symbol>::Cast(name);
1901 if (sym->Name()->IsUndefined())
1903 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
1906 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
1907 const v8::PropertyCallbackInfo<void>& info) {
1908 CHECK(name->IsSymbol());
1909 Local<Symbol> sym = Local<Symbol>::Cast(name);
1910 if (sym->Name()->IsUndefined())
1912 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
1915 void SymbolAccessorGetterReturnsDefault(
1916 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1917 CHECK(name->IsSymbol());
1918 Local<Symbol> sym = Local<Symbol>::Cast(name);
1919 if (sym->Name()->IsUndefined()) return;
1920 info.GetReturnValue().Set(info.Data());
1923 static void ThrowingSymbolAccessorGetter(
1924 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
1925 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
1929 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
1930 v8::Isolate* isolate = CcTest::isolate();
1931 v8::HandleScope scope(isolate);
1933 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
1934 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
1935 CHECK(a->map()->instance_descriptors()->IsFixedArray());
1936 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1937 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
1938 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
1939 // But we should still have an ExecutableAccessorInfo.
1940 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
1941 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
1942 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
1943 CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
1947 THREADED_TEST(UndefinedIsNotEnumerable) {
1949 v8::HandleScope scope(env->GetIsolate());
1950 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
1951 CHECK(result->IsFalse());
1955 v8::Handle<Script> call_recursively_script;
1956 static const int kTargetRecursionDepth = 200; // near maximum
1959 static void CallScriptRecursivelyCall(
1960 const v8::FunctionCallbackInfo<v8::Value>& args) {
1961 ApiTestFuzzer::Fuzz();
1962 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1963 if (depth == kTargetRecursionDepth) return;
1964 args.This()->Set(v8_str("depth"),
1965 v8::Integer::New(args.GetIsolate(), depth + 1));
1966 args.GetReturnValue().Set(call_recursively_script->Run());
1970 static void CallFunctionRecursivelyCall(
1971 const v8::FunctionCallbackInfo<v8::Value>& args) {
1972 ApiTestFuzzer::Fuzz();
1973 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
1974 if (depth == kTargetRecursionDepth) {
1975 printf("[depth = %d]\n", depth);
1978 args.This()->Set(v8_str("depth"),
1979 v8::Integer::New(args.GetIsolate(), depth + 1));
1980 v8::Handle<Value> function =
1981 args.This()->Get(v8_str("callFunctionRecursively"));
1982 args.GetReturnValue().Set(
1983 function.As<Function>()->Call(args.This(), 0, NULL));
1987 THREADED_TEST(DeepCrossLanguageRecursion) {
1988 v8::Isolate* isolate = CcTest::isolate();
1989 v8::HandleScope scope(isolate);
1990 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
1991 global->Set(v8_str("callScriptRecursively"),
1992 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
1993 global->Set(v8_str("callFunctionRecursively"),
1994 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
1995 LocalContext env(NULL, global);
1997 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
1998 call_recursively_script = v8_compile("callScriptRecursively()");
1999 call_recursively_script->Run();
2000 call_recursively_script = v8::Handle<Script>();
2002 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2003 CompileRun("callFunctionRecursively()");
2007 static void ThrowingPropertyHandlerGet(
2008 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2009 // Since this interceptor is used on "with" objects, the runtime will look up
2010 // @@unscopables. Punt.
2011 if (key->IsSymbol()) return;
2012 ApiTestFuzzer::Fuzz();
2013 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2017 static void ThrowingPropertyHandlerSet(
2018 Local<Name> key, Local<Value>,
2019 const v8::PropertyCallbackInfo<v8::Value>& info) {
2020 info.GetIsolate()->ThrowException(key);
2021 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2025 THREADED_TEST(CallbackExceptionRegression) {
2026 v8::Isolate* isolate = CcTest::isolate();
2027 v8::HandleScope scope(isolate);
2028 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2029 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2030 ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2032 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2033 v8::Handle<Value> otto =
2034 CompileRun("try { with (obj) { otto; } } catch (e) { e; }");
2035 CHECK(v8_str("otto")->Equals(otto));
2036 v8::Handle<Value> netto =
2037 CompileRun("try { with (obj) { netto = 4; } } catch (e) { e; }");
2038 CHECK(v8_str("netto")->Equals(netto));
2042 THREADED_TEST(FunctionPrototype) {
2043 v8::Isolate* isolate = CcTest::isolate();
2044 v8::HandleScope scope(isolate);
2045 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2046 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2048 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2049 Local<Script> script = v8_compile("Foo.prototype.plak");
2050 CHECK_EQ(script->Run()->Int32Value(), 321);
2054 THREADED_TEST(InternalFields) {
2056 v8::Isolate* isolate = env->GetIsolate();
2057 v8::HandleScope scope(isolate);
2059 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2060 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2061 instance_templ->SetInternalFieldCount(1);
2062 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2063 CHECK_EQ(1, obj->InternalFieldCount());
2064 CHECK(obj->GetInternalField(0)->IsUndefined());
2065 obj->SetInternalField(0, v8_num(17));
2066 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2070 THREADED_TEST(GlobalObjectInternalFields) {
2071 v8::Isolate* isolate = CcTest::isolate();
2072 v8::HandleScope scope(isolate);
2073 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2074 global_template->SetInternalFieldCount(1);
2075 LocalContext env(NULL, global_template);
2076 v8::Handle<v8::Object> global_proxy = env->Global();
2077 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2078 CHECK_EQ(1, global->InternalFieldCount());
2079 CHECK(global->GetInternalField(0)->IsUndefined());
2080 global->SetInternalField(0, v8_num(17));
2081 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2085 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2087 v8::HandleScope scope(CcTest::isolate());
2089 v8::Local<v8::Object> global = env->Global();
2090 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2091 CHECK(global->HasRealIndexedProperty(0));
2095 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2097 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2098 obj->SetAlignedPointerInInternalField(0, value);
2099 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2100 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2104 THREADED_TEST(InternalFieldsAlignedPointers) {
2106 v8::Isolate* isolate = env->GetIsolate();
2107 v8::HandleScope scope(isolate);
2109 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2110 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2111 instance_templ->SetInternalFieldCount(1);
2112 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2113 CHECK_EQ(1, obj->InternalFieldCount());
2115 CheckAlignedPointerInInternalField(obj, NULL);
2117 int* heap_allocated = new int[100];
2118 CheckAlignedPointerInInternalField(obj, heap_allocated);
2119 delete[] heap_allocated;
2121 int stack_allocated[100];
2122 CheckAlignedPointerInInternalField(obj, stack_allocated);
2124 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2125 CheckAlignedPointerInInternalField(obj, huge);
2127 v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2128 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2129 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2133 static void CheckAlignedPointerInEmbedderData(LocalContext* env, int index,
2135 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2136 (*env)->SetAlignedPointerInEmbedderData(index, value);
2137 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2138 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2142 static void* AlignedTestPointer(int i) {
2143 return reinterpret_cast<void*>(i * 1234);
2147 THREADED_TEST(EmbedderDataAlignedPointers) {
2149 v8::HandleScope scope(env->GetIsolate());
2151 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2153 int* heap_allocated = new int[100];
2154 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2155 delete[] heap_allocated;
2157 int stack_allocated[100];
2158 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2160 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2161 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2163 // Test growing of the embedder data's backing store.
2164 for (int i = 0; i < 100; i++) {
2165 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2167 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2168 for (int i = 0; i < 100; i++) {
2169 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2174 static void CheckEmbedderData(LocalContext* env, int index,
2175 v8::Handle<Value> data) {
2176 (*env)->SetEmbedderData(index, data);
2177 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2181 THREADED_TEST(EmbedderData) {
2183 v8::Isolate* isolate = env->GetIsolate();
2184 v8::HandleScope scope(isolate);
2187 &env, 3, v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2188 CheckEmbedderData(&env, 2,
2189 v8::String::NewFromUtf8(isolate, "over the lazy dog."));
2190 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2191 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2195 THREADED_TEST(GetIsolate) {
2197 v8::Isolate* isolate = env->GetIsolate();
2198 v8::HandleScope scope(isolate);
2199 Local<v8::Object> obj = v8::Object::New(isolate);
2200 CHECK_EQ(isolate, obj->GetIsolate());
2201 CHECK_EQ(isolate, CcTest::global()->GetIsolate());
2205 THREADED_TEST(IdentityHash) {
2207 v8::Isolate* isolate = env->GetIsolate();
2208 v8::HandleScope scope(isolate);
2210 // Ensure that the test starts with an fresh heap to test whether the hash
2211 // code is based on the address.
2212 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2213 Local<v8::Object> obj = v8::Object::New(isolate);
2214 int hash = obj->GetIdentityHash();
2215 int hash1 = obj->GetIdentityHash();
2216 CHECK_EQ(hash, hash1);
2217 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2218 // Since the identity hash is essentially a random number two consecutive
2219 // objects should not be assigned the same hash code. If the test below fails
2220 // the random number generator should be evaluated.
2221 CHECK_NE(hash, hash2);
2222 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2223 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2224 // Make sure that the identity hash is not based on the initial address of
2225 // the object alone. If the test below fails the random number generator
2226 // should be evaluated.
2227 CHECK_NE(hash, hash3);
2228 int hash4 = obj->GetIdentityHash();
2229 CHECK_EQ(hash, hash4);
2231 // Check identity hashes behaviour in the presence of JS accessors.
2232 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2234 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2235 Local<v8::Object> o1 = v8::Object::New(isolate);
2236 Local<v8::Object> o2 = v8::Object::New(isolate);
2237 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2241 "function cnst() { return 42; };\n"
2242 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2243 Local<v8::Object> o1 = v8::Object::New(isolate);
2244 Local<v8::Object> o2 = v8::Object::New(isolate);
2245 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2250 THREADED_TEST(GlobalProxyIdentityHash) {
2252 v8::Isolate* isolate = env->GetIsolate();
2253 v8::HandleScope scope(isolate);
2254 Handle<Object> global_proxy = env->Global();
2255 int hash1 = global_proxy->GetIdentityHash();
2256 // Hash should be retained after being detached.
2257 env->DetachGlobal();
2258 int hash2 = global_proxy->GetIdentityHash();
2259 CHECK_EQ(hash1, hash2);
2261 // Re-attach global proxy to a new context, hash should stay the same.
2262 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2263 int hash3 = global_proxy->GetIdentityHash();
2264 CHECK_EQ(hash1, hash3);
2269 TEST(SymbolIdentityHash) {
2271 v8::Isolate* isolate = env->GetIsolate();
2272 v8::HandleScope scope(isolate);
2275 Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
2276 int hash = symbol->GetIdentityHash();
2277 int hash1 = symbol->GetIdentityHash();
2278 CHECK_EQ(hash, hash1);
2279 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2280 int hash3 = symbol->GetIdentityHash();
2281 CHECK_EQ(hash, hash3);
2285 v8::Handle<v8::Symbol> js_symbol =
2286 CompileRun("Symbol('foo')").As<v8::Symbol>();
2287 int hash = js_symbol->GetIdentityHash();
2288 int hash1 = js_symbol->GetIdentityHash();
2289 CHECK_EQ(hash, hash1);
2290 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2291 int hash3 = js_symbol->GetIdentityHash();
2292 CHECK_EQ(hash, hash3);
2297 TEST(StringIdentityHash) {
2299 v8::Isolate* isolate = env->GetIsolate();
2300 v8::HandleScope scope(isolate);
2302 Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
2303 int hash = str->GetIdentityHash();
2304 int hash1 = str->GetIdentityHash();
2305 CHECK_EQ(hash, hash1);
2306 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2307 int hash3 = str->GetIdentityHash();
2308 CHECK_EQ(hash, hash3);
2310 Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
2311 int hash4 = str2->GetIdentityHash();
2312 CHECK_EQ(hash, hash4);
2316 THREADED_TEST(SymbolProperties) {
2318 v8::Isolate* isolate = env->GetIsolate();
2319 v8::HandleScope scope(isolate);
2321 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2322 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2323 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, v8_str("my-symbol"));
2324 v8::Local<v8::Symbol> sym3 = v8::Symbol::New(isolate, v8_str("sym3"));
2326 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2328 // Check basic symbol functionality.
2329 CHECK(sym1->IsSymbol());
2330 CHECK(sym2->IsSymbol());
2331 CHECK(!obj->IsSymbol());
2333 CHECK(sym1->Equals(sym1));
2334 CHECK(sym2->Equals(sym2));
2335 CHECK(!sym1->Equals(sym2));
2336 CHECK(!sym2->Equals(sym1));
2337 CHECK(sym1->StrictEquals(sym1));
2338 CHECK(sym2->StrictEquals(sym2));
2339 CHECK(!sym1->StrictEquals(sym2));
2340 CHECK(!sym2->StrictEquals(sym1));
2342 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2344 v8::Local<v8::Value> sym_val = sym2;
2345 CHECK(sym_val->IsSymbol());
2346 CHECK(sym_val->Equals(sym2));
2347 CHECK(sym_val->StrictEquals(sym2));
2348 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2350 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2351 CHECK(sym_obj->IsSymbolObject());
2352 CHECK(!sym2->IsSymbolObject());
2353 CHECK(!obj->IsSymbolObject());
2354 CHECK(!sym_obj->Equals(sym2));
2355 CHECK(!sym_obj->StrictEquals(sym2));
2356 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2357 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2359 // Make sure delete of a non-existent symbol property works.
2360 CHECK(obj->Delete(sym1));
2361 CHECK(!obj->Has(sym1));
2363 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2364 CHECK(obj->Has(sym1));
2365 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2366 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2367 CHECK(obj->Has(sym1));
2368 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2369 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2371 CHECK_EQ(0u, obj->GetOwnPropertyNames()->Length());
2372 unsigned num_props = obj->GetPropertyNames()->Length();
2373 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2374 v8::Integer::New(isolate, 20)));
2375 CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2376 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2378 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2380 CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2381 CHECK(obj->Get(sym3)->IsUndefined());
2382 CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2383 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2384 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2385 ->Equals(v8::Integer::New(isolate, 42)));
2387 // Add another property and delete it afterwards to force the object in
2389 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2390 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2391 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2392 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2393 CHECK_EQ(2u, obj->GetOwnPropertyNames()->Length());
2395 CHECK(obj->Has(sym1));
2396 CHECK(obj->Has(sym2));
2397 CHECK(obj->Has(sym3));
2398 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2399 CHECK(obj->Delete(sym2));
2400 CHECK(obj->Has(sym1));
2401 CHECK(!obj->Has(sym2));
2402 CHECK(obj->Has(sym3));
2403 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2404 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2405 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2406 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2407 ->Equals(v8::Integer::New(isolate, 42)));
2408 CHECK_EQ(2u, obj->GetOwnPropertyNames()->Length());
2410 // Symbol properties are inherited.
2411 v8::Local<v8::Object> child = v8::Object::New(isolate);
2412 child->SetPrototype(obj);
2413 CHECK(child->Has(sym1));
2414 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
2415 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2416 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))
2417 ->Equals(v8::Integer::New(isolate, 42)));
2418 CHECK_EQ(0u, child->GetOwnPropertyNames()->Length());
2422 THREADED_TEST(SymbolTemplateProperties) {
2424 v8::Isolate* isolate = env->GetIsolate();
2425 v8::HandleScope scope(isolate);
2426 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
2427 v8::Local<v8::Name> name = v8::Symbol::New(isolate);
2428 CHECK(!name.IsEmpty());
2429 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
2430 v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
2431 CHECK(!new_instance.IsEmpty());
2432 CHECK(new_instance->Has(name));
2436 THREADED_TEST(PrivateProperties) {
2438 v8::Isolate* isolate = env->GetIsolate();
2439 v8::HandleScope scope(isolate);
2441 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2442 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
2443 v8::Local<v8::Private> priv2 =
2444 v8::Private::New(isolate, v8_str("my-private"));
2446 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2448 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
2450 // Make sure delete of a non-existent private symbol property works.
2451 CHECK(obj->DeletePrivate(priv1));
2452 CHECK(!obj->HasPrivate(priv1));
2454 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
2455 CHECK(obj->HasPrivate(priv1));
2456 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
2457 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
2458 CHECK(obj->HasPrivate(priv1));
2459 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2461 CHECK_EQ(0u, obj->GetOwnPropertyNames()->Length());
2462 unsigned num_props = obj->GetPropertyNames()->Length();
2463 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2464 v8::Integer::New(isolate, 20)));
2465 CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2466 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2468 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2470 // Add another property and delete it afterwards to force the object in
2472 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
2473 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2474 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
2475 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2476 CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2478 CHECK(obj->HasPrivate(priv1));
2479 CHECK(obj->HasPrivate(priv2));
2480 CHECK(obj->DeletePrivate(priv2));
2481 CHECK(obj->HasPrivate(priv1));
2482 CHECK(!obj->HasPrivate(priv2));
2483 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
2484 CHECK_EQ(1u, obj->GetOwnPropertyNames()->Length());
2486 // Private properties are inherited (for the time being).
2487 v8::Local<v8::Object> child = v8::Object::New(isolate);
2488 child->SetPrototype(obj);
2489 CHECK(child->HasPrivate(priv1));
2490 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
2491 CHECK_EQ(0u, child->GetOwnPropertyNames()->Length());
2495 THREADED_TEST(GlobalSymbols) {
2497 v8::Isolate* isolate = env->GetIsolate();
2498 v8::HandleScope scope(isolate);
2500 v8::Local<String> name = v8_str("my-symbol");
2501 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
2502 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
2503 CHECK(glob2->SameValue(glob));
2505 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
2506 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
2507 CHECK(glob_api2->SameValue(glob_api));
2508 CHECK(!glob_api->SameValue(glob));
2510 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
2511 CHECK(!sym->SameValue(glob));
2513 CompileRun("var sym2 = Symbol.for('my-symbol')");
2514 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
2515 CHECK(sym2->SameValue(glob));
2516 CHECK(!sym2->SameValue(glob_api));
2520 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
2523 v8::Isolate* isolate = env->GetIsolate();
2524 v8::HandleScope scope(isolate);
2526 v8::Local<v8::Symbol> symbol = getter(isolate);
2527 std::string script = std::string("var sym = ") + name;
2528 CompileRun(script.c_str());
2529 v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
2531 CHECK(!value.IsEmpty());
2532 CHECK(!symbol.IsEmpty());
2533 CHECK(value->SameValue(symbol));
2537 THREADED_TEST(WellKnownSymbols) {
2538 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
2539 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
2543 THREADED_TEST(GlobalPrivates) {
2545 v8::Isolate* isolate = env->GetIsolate();
2546 v8::HandleScope scope(isolate);
2548 v8::Local<String> name = v8_str("my-private");
2549 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
2550 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2551 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
2553 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
2554 CHECK(obj->HasPrivate(glob2));
2556 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
2557 CHECK(!obj->HasPrivate(priv));
2559 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
2560 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
2561 CHECK(!obj->Has(intern));
2565 class ScopedArrayBufferContents {
2567 explicit ScopedArrayBufferContents(const v8::ArrayBuffer::Contents& contents)
2568 : contents_(contents) {}
2569 ~ScopedArrayBufferContents() { free(contents_.Data()); }
2570 void* Data() const { return contents_.Data(); }
2571 size_t ByteLength() const { return contents_.ByteLength(); }
2574 const v8::ArrayBuffer::Contents contents_;
2577 template <typename T>
2578 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
2579 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
2580 for (int i = 0; i < value->InternalFieldCount(); i++) {
2581 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
2586 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
2588 v8::Isolate* isolate = env->GetIsolate();
2589 v8::HandleScope handle_scope(isolate);
2591 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
2592 CheckInternalFieldsAreZero(ab);
2593 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
2594 CHECK(!ab->IsExternal());
2595 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2597 ScopedArrayBufferContents ab_contents(ab->Externalize());
2598 CHECK(ab->IsExternal());
2600 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
2601 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
2602 DCHECK(data != NULL);
2603 env->Global()->Set(v8_str("ab"), ab);
2605 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
2606 CHECK_EQ(1024, result->Int32Value());
2608 result = CompileRun(
2609 "var u8 = new Uint8Array(ab);"
2613 CHECK_EQ(1024, result->Int32Value());
2614 CHECK_EQ(0xFF, data[0]);
2615 CHECK_EQ(0xAA, data[1]);
2618 result = CompileRun("u8[0] + u8[1]");
2619 CHECK_EQ(0xDD, result->Int32Value());
2623 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
2625 v8::Isolate* isolate = env->GetIsolate();
2626 v8::HandleScope handle_scope(isolate);
2629 v8::Local<v8::Value> result = CompileRun(
2630 "var ab1 = new ArrayBuffer(2);"
2631 "var u8_a = new Uint8Array(ab1);"
2633 "u8_a[1] = 0xFF; u8_a.buffer");
2634 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
2635 CheckInternalFieldsAreZero(ab1);
2636 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
2637 CHECK(!ab1->IsExternal());
2638 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
2639 CHECK(ab1->IsExternal());
2641 result = CompileRun("ab1.byteLength");
2642 CHECK_EQ(2, result->Int32Value());
2643 result = CompileRun("u8_a[0]");
2644 CHECK_EQ(0xAA, result->Int32Value());
2645 result = CompileRun("u8_a[1]");
2646 CHECK_EQ(0xFF, result->Int32Value());
2647 result = CompileRun(
2648 "var u8_b = new Uint8Array(ab1);"
2651 CHECK_EQ(0xBB, result->Int32Value());
2652 result = CompileRun("u8_b[1]");
2653 CHECK_EQ(0xFF, result->Int32Value());
2655 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
2656 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
2657 CHECK_EQ(0xBB, ab1_data[0]);
2658 CHECK_EQ(0xFF, ab1_data[1]);
2661 result = CompileRun("u8_a[0] + u8_a[1]");
2662 CHECK_EQ(0xDD, result->Int32Value());
2666 THREADED_TEST(ArrayBuffer_External) {
2668 v8::Isolate* isolate = env->GetIsolate();
2669 v8::HandleScope handle_scope(isolate);
2671 i::ScopedVector<uint8_t> my_data(100);
2672 memset(my_data.start(), 0, 100);
2673 Local<v8::ArrayBuffer> ab3 =
2674 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
2675 CheckInternalFieldsAreZero(ab3);
2676 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
2677 CHECK(ab3->IsExternal());
2679 env->Global()->Set(v8_str("ab3"), ab3);
2681 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
2682 CHECK_EQ(100, result->Int32Value());
2684 result = CompileRun(
2685 "var u8_b = new Uint8Array(ab3);"
2689 CHECK_EQ(100, result->Int32Value());
2690 CHECK_EQ(0xBB, my_data[0]);
2691 CHECK_EQ(0xCC, my_data[1]);
2694 result = CompileRun("u8_b[0] + u8_b[1]");
2695 CHECK_EQ(0xDD, result->Int32Value());
2699 THREADED_TEST(ArrayBuffer_DisableNeuter) {
2701 v8::Isolate* isolate = env->GetIsolate();
2702 v8::HandleScope handle_scope(isolate);
2704 i::ScopedVector<uint8_t> my_data(100);
2705 memset(my_data.start(), 0, 100);
2706 Local<v8::ArrayBuffer> ab =
2707 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
2708 CHECK(ab->IsNeuterable());
2710 i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
2711 buf->set_is_neuterable(false);
2713 CHECK(!ab->IsNeuterable());
2717 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
2718 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
2719 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
2723 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
2724 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
2725 CHECK_EQ(0, static_cast<int>(ta->Length()));
2726 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
2730 static void CheckIsTypedArrayVarNeutered(const char* name) {
2731 i::ScopedVector<char> source(1024);
2733 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
2735 CHECK(CompileRun(source.start())->IsTrue());
2736 v8::Handle<v8::TypedArray> ta =
2737 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
2738 CheckIsNeutered(ta);
2742 template <typename TypedArray, int kElementSize>
2743 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
2744 int byteOffset, int length) {
2745 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
2746 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
2747 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
2748 CHECK_EQ(length, static_cast<int>(ta->Length()));
2749 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
2754 THREADED_TEST(ArrayBuffer_NeuteringApi) {
2756 v8::Isolate* isolate = env->GetIsolate();
2757 v8::HandleScope handle_scope(isolate);
2759 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
2761 v8::Handle<v8::Uint8Array> u8a =
2762 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
2763 v8::Handle<v8::Uint8ClampedArray> u8c =
2764 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
2765 v8::Handle<v8::Int8Array> i8a =
2766 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
2768 v8::Handle<v8::Uint16Array> u16a =
2769 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
2770 v8::Handle<v8::Int16Array> i16a =
2771 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
2773 v8::Handle<v8::Uint32Array> u32a =
2774 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
2775 v8::Handle<v8::Int32Array> i32a =
2776 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
2778 v8::Handle<v8::Float32Array> f32a =
2779 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
2780 v8::Handle<v8::Float64Array> f64a =
2781 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
2783 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
2784 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
2785 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
2786 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
2788 ScopedArrayBufferContents contents(buffer->Externalize());
2790 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
2791 CheckIsNeutered(u8a);
2792 CheckIsNeutered(u8c);
2793 CheckIsNeutered(i8a);
2794 CheckIsNeutered(u16a);
2795 CheckIsNeutered(i16a);
2796 CheckIsNeutered(u32a);
2797 CheckIsNeutered(i32a);
2798 CheckIsNeutered(f32a);
2799 CheckIsNeutered(f64a);
2800 CheckDataViewIsNeutered(dv);
2804 THREADED_TEST(ArrayBuffer_NeuteringScript) {
2806 v8::Isolate* isolate = env->GetIsolate();
2807 v8::HandleScope handle_scope(isolate);
2810 "var ab = new ArrayBuffer(1024);"
2811 "var u8a = new Uint8Array(ab, 1, 1023);"
2812 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
2813 "var i8a = new Int8Array(ab, 1, 1023);"
2814 "var u16a = new Uint16Array(ab, 2, 511);"
2815 "var i16a = new Int16Array(ab, 2, 511);"
2816 "var u32a = new Uint32Array(ab, 4, 255);"
2817 "var i32a = new Int32Array(ab, 4, 255);"
2818 "var f32a = new Float32Array(ab, 4, 255);"
2819 "var f64a = new Float64Array(ab, 8, 127);"
2820 "var dv = new DataView(ab, 1, 1023);");
2822 v8::Handle<v8::ArrayBuffer> ab =
2823 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
2825 v8::Handle<v8::DataView> dv =
2826 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
2828 ScopedArrayBufferContents contents(ab->Externalize());
2830 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
2831 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
2833 CheckIsTypedArrayVarNeutered("u8a");
2834 CheckIsTypedArrayVarNeutered("u8c");
2835 CheckIsTypedArrayVarNeutered("i8a");
2836 CheckIsTypedArrayVarNeutered("u16a");
2837 CheckIsTypedArrayVarNeutered("i16a");
2838 CheckIsTypedArrayVarNeutered("u32a");
2839 CheckIsTypedArrayVarNeutered("i32a");
2840 CheckIsTypedArrayVarNeutered("f32a");
2841 CheckIsTypedArrayVarNeutered("f64a");
2843 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
2844 CheckDataViewIsNeutered(dv);
2848 THREADED_TEST(HiddenProperties) {
2850 v8::Isolate* isolate = env->GetIsolate();
2851 v8::HandleScope scope(isolate);
2853 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
2854 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
2855 v8::Local<v8::String> empty = v8_str("");
2856 v8::Local<v8::String> prop_name = v8_str("prop_name");
2858 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2860 // Make sure delete of a non-existent hidden value works
2861 CHECK(obj->DeleteHiddenValue(key));
2863 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
2864 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
2865 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
2866 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2868 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2870 // Make sure we do not find the hidden property.
2871 CHECK(!obj->Has(empty));
2872 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2873 CHECK(obj->Get(empty)->IsUndefined());
2874 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2875 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
2876 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2877 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
2879 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2881 // Add another property and delete it afterwards to force the object in
2883 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
2884 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2885 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
2886 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2887 CHECK(obj->Delete(prop_name));
2888 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
2890 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2892 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
2893 CHECK(obj->GetHiddenValue(key).IsEmpty());
2895 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
2896 CHECK(obj->DeleteHiddenValue(key));
2897 CHECK(obj->GetHiddenValue(key).IsEmpty());
2901 THREADED_TEST(Regress97784) {
2902 // Regression test for crbug.com/97784
2903 // Messing with the Object.prototype should not have effect on
2904 // hidden properties.
2906 v8::HandleScope scope(env->GetIsolate());
2908 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
2909 v8::Local<v8::String> key = v8_str("hidden");
2912 "set_called = false;"
2913 "Object.defineProperty("
2914 " Object.prototype,"
2916 " {get: function() { return 45; },"
2917 " set: function() { set_called = true; }})");
2919 CHECK(obj->GetHiddenValue(key).IsEmpty());
2920 // Make sure that the getter and setter from Object.prototype is not invoked.
2921 // If it did we would have full access to the hidden properties in
2923 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
2924 ExpectFalse("set_called");
2925 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
2929 THREADED_TEST(External) {
2930 v8::HandleScope scope(CcTest::isolate());
2932 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
2934 env->Global()->Set(v8_str("ext"), ext);
2935 Local<Value> reext_obj = CompileRun("this.ext");
2936 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
2937 int* ptr = static_cast<int*>(reext->Value());
2942 // Make sure unaligned pointers are wrapped properly.
2943 char* data = i::StrDup("0123456789");
2944 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
2945 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
2946 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
2947 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
2949 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
2950 CHECK_EQ('0', *char_ptr);
2951 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
2952 CHECK_EQ('1', *char_ptr);
2953 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
2954 CHECK_EQ('2', *char_ptr);
2955 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
2956 CHECK_EQ('3', *char_ptr);
2957 i::DeleteArray(data);
2961 THREADED_TEST(GlobalHandle) {
2962 v8::Isolate* isolate = CcTest::isolate();
2963 v8::Persistent<String> global;
2965 v8::HandleScope scope(isolate);
2966 global.Reset(isolate, v8_str("str"));
2969 v8::HandleScope scope(isolate);
2970 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
2974 v8::HandleScope scope(isolate);
2975 global.Reset(isolate, v8_str("str"));
2978 v8::HandleScope scope(isolate);
2979 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
2985 THREADED_TEST(ResettingGlobalHandle) {
2986 v8::Isolate* isolate = CcTest::isolate();
2987 v8::Persistent<String> global;
2989 v8::HandleScope scope(isolate);
2990 global.Reset(isolate, v8_str("str"));
2992 v8::internal::GlobalHandles* global_handles =
2993 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
2994 int initial_handle_count = global_handles->global_handles_count();
2996 v8::HandleScope scope(isolate);
2997 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3000 v8::HandleScope scope(isolate);
3001 global.Reset(isolate, v8_str("longer"));
3003 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3005 v8::HandleScope scope(isolate);
3006 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3009 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3013 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3014 v8::Isolate* isolate = CcTest::isolate();
3015 v8::Persistent<String> global;
3017 v8::HandleScope scope(isolate);
3018 global.Reset(isolate, v8_str("str"));
3020 v8::internal::GlobalHandles* global_handles =
3021 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3022 int initial_handle_count = global_handles->global_handles_count();
3024 v8::HandleScope scope(isolate);
3025 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3028 v8::HandleScope scope(isolate);
3029 Local<String> empty;
3030 global.Reset(isolate, empty);
3032 CHECK(global.IsEmpty());
3033 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3038 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3039 return unique.Pass();
3044 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3045 const v8::Persistent<T>& global) {
3046 v8::UniquePersistent<String> unique(isolate, global);
3047 return unique.Pass();
3051 THREADED_TEST(UniquePersistent) {
3052 v8::Isolate* isolate = CcTest::isolate();
3053 v8::Persistent<String> global;
3055 v8::HandleScope scope(isolate);
3056 global.Reset(isolate, v8_str("str"));
3058 v8::internal::GlobalHandles* global_handles =
3059 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3060 int initial_handle_count = global_handles->global_handles_count();
3062 v8::UniquePersistent<String> unique(isolate, global);
3063 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3064 // Test assignment via Pass
3066 v8::UniquePersistent<String> copy = unique.Pass();
3067 CHECK(unique.IsEmpty());
3068 CHECK(copy == global);
3069 CHECK_EQ(initial_handle_count + 1,
3070 global_handles->global_handles_count());
3071 unique = copy.Pass();
3073 // Test ctor via Pass
3075 v8::UniquePersistent<String> copy(unique.Pass());
3076 CHECK(unique.IsEmpty());
3077 CHECK(copy == global);
3078 CHECK_EQ(initial_handle_count + 1,
3079 global_handles->global_handles_count());
3080 unique = copy.Pass();
3082 // Test pass through function call
3084 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3085 CHECK(unique.IsEmpty());
3086 CHECK(copy == global);
3087 CHECK_EQ(initial_handle_count + 1,
3088 global_handles->global_handles_count());
3089 unique = copy.Pass();
3091 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3093 // Test pass from function call
3095 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3096 CHECK(unique == global);
3097 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3099 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3104 template <typename K, typename V>
3105 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3107 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V>> MapType;
3108 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3109 struct WeakCallbackDataType {
3113 static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
3115 WeakCallbackDataType* data = new WeakCallbackDataType;
3120 static MapType* MapFromWeakCallbackData(
3121 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3122 return data.GetParameter()->map;
3124 static K KeyFromWeakCallbackData(
3125 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3126 return data.GetParameter()->key;
3128 static void DisposeCallbackData(WeakCallbackDataType* data) { delete data; }
3129 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3134 template <typename Map>
3135 static void TestPersistentValueMap() {
3137 v8::Isolate* isolate = env->GetIsolate();
3139 v8::internal::GlobalHandles* global_handles =
3140 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3141 int initial_handle_count = global_handles->global_handles_count();
3142 CHECK_EQ(0, static_cast<int>(map.Size()));
3144 HandleScope scope(isolate);
3145 Local<v8::Object> obj = map.Get(7);
3146 CHECK(obj.IsEmpty());
3147 Local<v8::Object> expected = v8::Object::New(isolate);
3148 map.Set(7, expected);
3149 CHECK_EQ(1, static_cast<int>(map.Size()));
3151 CHECK(expected->Equals(obj));
3153 typename Map::PersistentValueReference ref = map.GetReference(7);
3154 CHECK(expected->Equals(ref.NewLocal(isolate)));
3156 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3157 CHECK_EQ(0, static_cast<int>(map.Size()));
3158 CHECK(expected == removed);
3159 removed = map.Remove(7);
3160 CHECK(removed.IsEmpty());
3161 map.Set(8, expected);
3162 CHECK_EQ(1, static_cast<int>(map.Size()));
3163 map.Set(8, expected);
3164 CHECK_EQ(1, static_cast<int>(map.Size()));
3166 typename Map::PersistentValueReference ref;
3167 Local<v8::Object> expected2 = v8::Object::New(isolate);
3168 removed = map.Set(8, v8::UniquePersistent<v8::Object>(isolate, expected2),
3170 CHECK_EQ(1, static_cast<int>(map.Size()));
3171 CHECK(expected == removed);
3172 CHECK(expected2->Equals(ref.NewLocal(isolate)));
3175 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3177 reinterpret_cast<v8::internal::Isolate*>(isolate)
3179 ->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3183 CHECK_EQ(0, static_cast<int>(map.Size()));
3184 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3188 TEST(PersistentValueMap) {
3189 // Default case, w/o weak callbacks:
3190 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object>>();
3192 // Custom traits with weak callbacks:
3193 typedef v8::PersistentValueMap<int, v8::Object,
3194 WeakStdMapTraits<int, v8::Object>>
3195 WeakPersistentValueMap;
3196 TestPersistentValueMap<WeakPersistentValueMap>();
3200 TEST(PersistentValueVector) {
3202 v8::Isolate* isolate = env->GetIsolate();
3203 v8::internal::GlobalHandles* global_handles =
3204 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3205 int handle_count = global_handles->global_handles_count();
3206 HandleScope scope(isolate);
3208 v8::PersistentValueVector<v8::Object> vector(isolate);
3210 Local<v8::Object> obj1 = v8::Object::New(isolate);
3211 Local<v8::Object> obj2 = v8::Object::New(isolate);
3212 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3214 CHECK(vector.IsEmpty());
3215 CHECK_EQ(0, static_cast<int>(vector.Size()));
3217 vector.ReserveCapacity(3);
3218 CHECK(vector.IsEmpty());
3220 vector.Append(obj1);
3221 vector.Append(obj2);
3222 vector.Append(obj1);
3223 vector.Append(obj3.Pass());
3224 vector.Append(obj1);
3226 CHECK(!vector.IsEmpty());
3227 CHECK_EQ(5, static_cast<int>(vector.Size()));
3228 CHECK(obj3.IsEmpty());
3229 CHECK(obj1->Equals(vector.Get(0)));
3230 CHECK(obj1->Equals(vector.Get(2)));
3231 CHECK(obj1->Equals(vector.Get(4)));
3232 CHECK(obj2->Equals(vector.Get(1)));
3234 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3237 CHECK(vector.IsEmpty());
3238 CHECK_EQ(0, static_cast<int>(vector.Size()));
3239 CHECK_EQ(handle_count, global_handles->global_handles_count());
3243 THREADED_TEST(GlobalHandleUpcast) {
3244 v8::Isolate* isolate = CcTest::isolate();
3245 v8::HandleScope scope(isolate);
3246 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3247 v8::Persistent<String> global_string(isolate, local);
3248 v8::Persistent<Value>& global_value =
3249 v8::Persistent<Value>::Cast(global_string);
3250 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3251 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3252 global_string.Reset();
3256 THREADED_TEST(HandleEquality) {
3257 v8::Isolate* isolate = CcTest::isolate();
3258 v8::Persistent<String> global1;
3259 v8::Persistent<String> global2;
3261 v8::HandleScope scope(isolate);
3262 global1.Reset(isolate, v8_str("str"));
3263 global2.Reset(isolate, v8_str("str2"));
3265 CHECK_EQ(global1 == global1, true);
3266 CHECK_EQ(global1 != global1, false);
3268 v8::HandleScope scope(isolate);
3269 Local<String> local1 = Local<String>::New(isolate, global1);
3270 Local<String> local2 = Local<String>::New(isolate, global2);
3272 CHECK_EQ(global1 == local1, true);
3273 CHECK_EQ(global1 != local1, false);
3274 CHECK_EQ(local1 == global1, true);
3275 CHECK_EQ(local1 != global1, false);
3277 CHECK_EQ(global1 == local2, false);
3278 CHECK_EQ(global1 != local2, true);
3279 CHECK_EQ(local2 == global1, false);
3280 CHECK_EQ(local2 != global1, true);
3282 CHECK_EQ(local1 == local2, false);
3283 CHECK_EQ(local1 != local2, true);
3285 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3286 CHECK_EQ(local1 == anotherLocal1, true);
3287 CHECK_EQ(local1 != anotherLocal1, false);
3294 THREADED_TEST(LocalHandle) {
3295 v8::HandleScope scope(CcTest::isolate());
3296 v8::Local<String> local =
3297 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3298 CHECK_EQ(local->Length(), 3);
3302 class WeakCallCounter {
3304 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) {}
3305 int id() { return id_; }
3306 void increment() { number_of_weak_calls_++; }
3307 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3311 int number_of_weak_calls_;
3315 template <typename T>
3316 struct WeakCallCounterAndPersistent {
3317 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3318 : counter(counter) {}
3319 WeakCallCounter* counter;
3320 v8::Persistent<T> handle;
3324 template <typename T>
3325 static void WeakPointerCallback(
3326 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T>>& data) {
3327 CHECK_EQ(1234, data.GetParameter()->counter->id());
3328 data.GetParameter()->counter->increment();
3329 data.GetParameter()->handle.Reset();
3333 template <typename T>
3334 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3335 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3339 THREADED_TEST(ApiObjectGroups) {
3341 v8::Isolate* iso = env->GetIsolate();
3342 HandleScope scope(iso);
3344 WeakCallCounter counter(1234);
3346 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3347 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3348 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3349 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3350 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3351 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3354 HandleScope scope(iso);
3355 g1s1.handle.Reset(iso, Object::New(iso));
3356 g1s2.handle.Reset(iso, Object::New(iso));
3357 g1c1.handle.Reset(iso, Object::New(iso));
3358 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3359 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3360 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3362 g2s1.handle.Reset(iso, Object::New(iso));
3363 g2s2.handle.Reset(iso, Object::New(iso));
3364 g2c1.handle.Reset(iso, Object::New(iso));
3365 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3366 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3367 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3370 WeakCallCounterAndPersistent<Value> root(&counter);
3371 root.handle.Reset(iso, g1s1.handle); // make a root.
3373 // Connect group 1 and 2, make a cycle.
3375 HandleScope scope(iso);
3376 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())
3377 ->Set(0, Local<Value>::New(iso, g2s2.handle)));
3378 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())
3379 ->Set(0, Local<Value>::New(iso, g1s1.handle)));
3383 UniqueId id1 = MakeUniqueId(g1s1.handle);
3384 UniqueId id2 = MakeUniqueId(g2s2.handle);
3385 iso->SetObjectGroupId(g1s1.handle, id1);
3386 iso->SetObjectGroupId(g1s2.handle, id1);
3387 iso->SetReferenceFromGroup(id1, g1c1.handle);
3388 iso->SetObjectGroupId(g2s1.handle, id2);
3389 iso->SetObjectGroupId(g2s2.handle, id2);
3390 iso->SetReferenceFromGroup(id2, g2c1.handle);
3392 // Do a single full GC, ensure incremental marking is stopped.
3393 v8::internal::Heap* heap =
3394 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3395 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3397 // All object should be alive.
3398 CHECK_EQ(0, counter.NumberOfWeakCalls());
3401 root.handle.SetWeak(&root, &WeakPointerCallback);
3402 // But make children strong roots---all the objects (except for children)
3403 // should be collectable now.
3404 g1c1.handle.ClearWeak();
3405 g2c1.handle.ClearWeak();
3407 // Groups are deleted, rebuild groups.
3409 UniqueId id1 = MakeUniqueId(g1s1.handle);
3410 UniqueId id2 = MakeUniqueId(g2s2.handle);
3411 iso->SetObjectGroupId(g1s1.handle, id1);
3412 iso->SetObjectGroupId(g1s2.handle, id1);
3413 iso->SetReferenceFromGroup(id1, g1c1.handle);
3414 iso->SetObjectGroupId(g2s1.handle, id2);
3415 iso->SetObjectGroupId(g2s2.handle, id2);
3416 iso->SetReferenceFromGroup(id2, g2c1.handle);
3419 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3421 // All objects should be gone. 5 global handles in total.
3422 CHECK_EQ(5, counter.NumberOfWeakCalls());
3424 // And now make children weak again and collect them.
3425 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3426 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3428 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3429 CHECK_EQ(7, counter.NumberOfWeakCalls());
3433 THREADED_TEST(ApiObjectGroupsForSubtypes) {
3435 v8::Isolate* iso = env->GetIsolate();
3436 HandleScope scope(iso);
3438 WeakCallCounter counter(1234);
3440 WeakCallCounterAndPersistent<Object> g1s1(&counter);
3441 WeakCallCounterAndPersistent<String> g1s2(&counter);
3442 WeakCallCounterAndPersistent<String> g1c1(&counter);
3443 WeakCallCounterAndPersistent<Object> g2s1(&counter);
3444 WeakCallCounterAndPersistent<String> g2s2(&counter);
3445 WeakCallCounterAndPersistent<String> g2c1(&counter);
3448 HandleScope scope(iso);
3449 g1s1.handle.Reset(iso, Object::New(iso));
3450 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
3451 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
3452 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3453 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3454 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3456 g2s1.handle.Reset(iso, Object::New(iso));
3457 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
3458 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
3459 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3460 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3461 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3464 WeakCallCounterAndPersistent<Value> root(&counter);
3465 root.handle.Reset(iso, g1s1.handle); // make a root.
3467 // Connect group 1 and 2, make a cycle.
3469 HandleScope scope(iso);
3470 CHECK(Local<Object>::New(iso, g1s1.handle)
3471 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
3472 CHECK(Local<Object>::New(iso, g2s1.handle)
3473 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
3477 UniqueId id1 = MakeUniqueId(g1s1.handle);
3478 UniqueId id2 = MakeUniqueId(g2s2.handle);
3479 iso->SetObjectGroupId(g1s1.handle, id1);
3480 iso->SetObjectGroupId(g1s2.handle, id1);
3481 iso->SetReference(g1s1.handle, g1c1.handle);
3482 iso->SetObjectGroupId(g2s1.handle, id2);
3483 iso->SetObjectGroupId(g2s2.handle, id2);
3484 iso->SetReferenceFromGroup(id2, g2c1.handle);
3486 // Do a single full GC, ensure incremental marking is stopped.
3487 v8::internal::Heap* heap =
3488 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3489 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3491 // All object should be alive.
3492 CHECK_EQ(0, counter.NumberOfWeakCalls());
3495 root.handle.SetWeak(&root, &WeakPointerCallback);
3496 // But make children strong roots---all the objects (except for children)
3497 // should be collectable now.
3498 g1c1.handle.ClearWeak();
3499 g2c1.handle.ClearWeak();
3501 // Groups are deleted, rebuild groups.
3503 UniqueId id1 = MakeUniqueId(g1s1.handle);
3504 UniqueId id2 = MakeUniqueId(g2s2.handle);
3505 iso->SetObjectGroupId(g1s1.handle, id1);
3506 iso->SetObjectGroupId(g1s2.handle, id1);
3507 iso->SetReference(g1s1.handle, g1c1.handle);
3508 iso->SetObjectGroupId(g2s1.handle, id2);
3509 iso->SetObjectGroupId(g2s2.handle, id2);
3510 iso->SetReferenceFromGroup(id2, g2c1.handle);
3513 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3515 // All objects should be gone. 5 global handles in total.
3516 CHECK_EQ(5, counter.NumberOfWeakCalls());
3518 // And now make children weak again and collect them.
3519 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3520 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3522 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3523 CHECK_EQ(7, counter.NumberOfWeakCalls());
3527 THREADED_TEST(ApiObjectGroupsCycle) {
3529 v8::Isolate* iso = env->GetIsolate();
3530 HandleScope scope(iso);
3532 WeakCallCounter counter(1234);
3534 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3535 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3536 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3537 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3538 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3539 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3540 WeakCallCounterAndPersistent<Value> g4s1(&counter);
3541 WeakCallCounterAndPersistent<Value> g4s2(&counter);
3544 HandleScope scope(iso);
3545 g1s1.handle.Reset(iso, Object::New(iso));
3546 g1s2.handle.Reset(iso, Object::New(iso));
3547 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3548 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3549 CHECK(g1s1.handle.IsWeak());
3550 CHECK(g1s2.handle.IsWeak());
3552 g2s1.handle.Reset(iso, Object::New(iso));
3553 g2s2.handle.Reset(iso, Object::New(iso));
3554 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3555 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3556 CHECK(g2s1.handle.IsWeak());
3557 CHECK(g2s2.handle.IsWeak());
3559 g3s1.handle.Reset(iso, Object::New(iso));
3560 g3s2.handle.Reset(iso, Object::New(iso));
3561 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3562 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3563 CHECK(g3s1.handle.IsWeak());
3564 CHECK(g3s2.handle.IsWeak());
3566 g4s1.handle.Reset(iso, Object::New(iso));
3567 g4s2.handle.Reset(iso, Object::New(iso));
3568 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
3569 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
3570 CHECK(g4s1.handle.IsWeak());
3571 CHECK(g4s2.handle.IsWeak());
3574 WeakCallCounterAndPersistent<Value> root(&counter);
3575 root.handle.Reset(iso, g1s1.handle); // make a root.
3577 // Connect groups. We're building the following cycle:
3578 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3581 UniqueId id1 = MakeUniqueId(g1s1.handle);
3582 UniqueId id2 = MakeUniqueId(g2s1.handle);
3583 UniqueId id3 = MakeUniqueId(g3s1.handle);
3584 UniqueId id4 = MakeUniqueId(g4s1.handle);
3585 iso->SetObjectGroupId(g1s1.handle, id1);
3586 iso->SetObjectGroupId(g1s2.handle, id1);
3587 iso->SetReferenceFromGroup(id1, g2s1.handle);
3588 iso->SetObjectGroupId(g2s1.handle, id2);
3589 iso->SetObjectGroupId(g2s2.handle, id2);
3590 iso->SetReferenceFromGroup(id2, g3s1.handle);
3591 iso->SetObjectGroupId(g3s1.handle, id3);
3592 iso->SetObjectGroupId(g3s2.handle, id3);
3593 iso->SetReferenceFromGroup(id3, g4s1.handle);
3594 iso->SetObjectGroupId(g4s1.handle, id4);
3595 iso->SetObjectGroupId(g4s2.handle, id4);
3596 iso->SetReferenceFromGroup(id4, g1s1.handle);
3598 // Do a single full GC
3599 v8::internal::Heap* heap =
3600 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3601 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3603 // All object should be alive.
3604 CHECK_EQ(0, counter.NumberOfWeakCalls());
3607 root.handle.SetWeak(&root, &WeakPointerCallback);
3609 // Groups are deleted, rebuild groups.
3611 UniqueId id1 = MakeUniqueId(g1s1.handle);
3612 UniqueId id2 = MakeUniqueId(g2s1.handle);
3613 UniqueId id3 = MakeUniqueId(g3s1.handle);
3614 UniqueId id4 = MakeUniqueId(g4s1.handle);
3615 iso->SetObjectGroupId(g1s1.handle, id1);
3616 iso->SetObjectGroupId(g1s2.handle, id1);
3617 iso->SetReferenceFromGroup(id1, g2s1.handle);
3618 iso->SetObjectGroupId(g2s1.handle, id2);
3619 iso->SetObjectGroupId(g2s2.handle, id2);
3620 iso->SetReferenceFromGroup(id2, g3s1.handle);
3621 iso->SetObjectGroupId(g3s1.handle, id3);
3622 iso->SetObjectGroupId(g3s2.handle, id3);
3623 iso->SetReferenceFromGroup(id3, g4s1.handle);
3624 iso->SetObjectGroupId(g4s1.handle, id4);
3625 iso->SetObjectGroupId(g4s2.handle, id4);
3626 iso->SetReferenceFromGroup(id4, g1s1.handle);
3629 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3631 // All objects should be gone. 9 global handles in total.
3632 CHECK_EQ(9, counter.NumberOfWeakCalls());
3636 THREADED_TEST(WeakRootsSurviveTwoRoundsOfGC) {
3638 v8::Isolate* iso = env->GetIsolate();
3639 HandleScope scope(iso);
3641 WeakCallCounter counter(1234);
3643 WeakCallCounterAndPersistent<Value> weak_obj(&counter);
3645 // Create a weak object that references a internalized string.
3647 HandleScope scope(iso);
3648 weak_obj.handle.Reset(iso, Object::New(iso));
3649 weak_obj.handle.SetWeak(&weak_obj, &WeakPointerCallback);
3650 CHECK(weak_obj.handle.IsWeak());
3651 Local<Object>::New(iso, weak_obj.handle.As<Object>())
3652 ->Set(v8_str("x"), String::NewFromUtf8(iso, "magic cookie",
3653 String::kInternalizedString));
3655 // Do a single full GC
3656 i::Isolate* i_iso = reinterpret_cast<v8::internal::Isolate*>(iso);
3657 i::Heap* heap = i_iso->heap();
3658 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3660 // We should have received the weak callback.
3661 CHECK_EQ(1, counter.NumberOfWeakCalls());
3663 // Check that the string is still alive.
3665 HandleScope scope(iso);
3666 i::MaybeHandle<i::String> magic_string =
3667 i::StringTable::LookupStringIfExists(
3669 v8::Utils::OpenHandle(*String::NewFromUtf8(iso, "magic cookie")));
3670 magic_string.Check();
3675 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
3676 // on the buildbots, so was made non-threaded for the time being.
3677 TEST(ApiObjectGroupsCycleForScavenger) {
3678 i::FLAG_stress_compaction = false;
3679 i::FLAG_gc_global = false;
3681 v8::Isolate* iso = env->GetIsolate();
3682 HandleScope scope(iso);
3684 WeakCallCounter counter(1234);
3686 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3687 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3688 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3689 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3690 WeakCallCounterAndPersistent<Value> g3s1(&counter);
3691 WeakCallCounterAndPersistent<Value> g3s2(&counter);
3694 HandleScope scope(iso);
3695 g1s1.handle.Reset(iso, Object::New(iso));
3696 g1s2.handle.Reset(iso, Object::New(iso));
3697 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3698 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3700 g2s1.handle.Reset(iso, Object::New(iso));
3701 g2s2.handle.Reset(iso, Object::New(iso));
3702 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3703 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3705 g3s1.handle.Reset(iso, Object::New(iso));
3706 g3s2.handle.Reset(iso, Object::New(iso));
3707 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
3708 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
3712 WeakCallCounterAndPersistent<Value> root(&counter);
3713 root.handle.Reset(iso, g1s1.handle);
3714 root.handle.MarkPartiallyDependent();
3716 // Connect groups. We're building the following cycle:
3717 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
3720 HandleScope handle_scope(iso);
3721 g1s1.handle.MarkPartiallyDependent();
3722 g1s2.handle.MarkPartiallyDependent();
3723 g2s1.handle.MarkPartiallyDependent();
3724 g2s2.handle.MarkPartiallyDependent();
3725 g3s1.handle.MarkPartiallyDependent();
3726 g3s2.handle.MarkPartiallyDependent();
3727 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3728 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3729 Local<Object>::New(iso, g1s1.handle.As<Object>())
3730 ->Set(v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3731 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3732 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3733 Local<Object>::New(iso, g2s1.handle.As<Object>())
3734 ->Set(v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3735 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3736 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3737 Local<Object>::New(iso, g3s1.handle.As<Object>())
3738 ->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3741 v8::internal::Heap* heap =
3742 reinterpret_cast<v8::internal::Isolate*>(iso)->heap();
3743 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
3745 // All objects should be alive.
3746 CHECK_EQ(0, counter.NumberOfWeakCalls());
3749 root.handle.SetWeak(&root, &WeakPointerCallback);
3750 root.handle.MarkPartiallyDependent();
3752 // Groups are deleted, rebuild groups.
3754 HandleScope handle_scope(iso);
3755 g1s1.handle.MarkPartiallyDependent();
3756 g1s2.handle.MarkPartiallyDependent();
3757 g2s1.handle.MarkPartiallyDependent();
3758 g2s2.handle.MarkPartiallyDependent();
3759 g3s1.handle.MarkPartiallyDependent();
3760 g3s2.handle.MarkPartiallyDependent();
3761 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
3762 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
3763 Local<Object>::New(iso, g1s1.handle.As<Object>())
3764 ->Set(v8_str("x"), Local<Value>::New(iso, g2s1.handle));
3765 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
3766 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
3767 Local<Object>::New(iso, g2s1.handle.As<Object>())
3768 ->Set(v8_str("x"), Local<Value>::New(iso, g3s1.handle));
3769 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
3770 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
3771 Local<Object>::New(iso, g3s1.handle.As<Object>())
3772 ->Set(v8_str("x"), Local<Value>::New(iso, g1s1.handle));
3775 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
3777 // All objects should be gone. 7 global handles in total.
3778 CHECK_EQ(7, counter.NumberOfWeakCalls());
3782 THREADED_TEST(ScriptException) {
3784 v8::HandleScope scope(env->GetIsolate());
3785 Local<Script> script = v8_compile("throw 'panama!';");
3786 v8::TryCatch try_catch;
3787 Local<Value> result = script->Run();
3788 CHECK(result.IsEmpty());
3789 CHECK(try_catch.HasCaught());
3790 String::Utf8Value exception_value(try_catch.Exception());
3791 CHECK_EQ(0, strcmp(*exception_value, "panama!"));
3795 TEST(TryCatchCustomException) {
3797 v8::Isolate* isolate = env->GetIsolate();
3798 v8::HandleScope scope(isolate);
3799 v8::TryCatch try_catch;
3801 "function CustomError() { this.a = 'b'; }"
3802 "(function f() { throw new CustomError(); })();");
3803 CHECK(try_catch.HasCaught());
3804 CHECK(try_catch.Exception()
3807 ->Equals(v8_str("b")));
3811 bool message_received;
3814 static void check_message_0(v8::Handle<v8::Message> message,
3815 v8::Handle<Value> data) {
3816 CHECK_EQ(5.76, data->NumberValue());
3817 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
3818 CHECK(!message->IsSharedCrossOrigin());
3819 message_received = true;
3823 THREADED_TEST(MessageHandler0) {
3824 message_received = false;
3825 v8::HandleScope scope(CcTest::isolate());
3826 CHECK(!message_received);
3827 LocalContext context;
3828 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
3829 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
3831 CHECK(message_received);
3832 // clear out the message listener
3833 v8::V8::RemoveMessageListeners(check_message_0);
3837 static void check_message_1(v8::Handle<v8::Message> message,
3838 v8::Handle<Value> data) {
3839 CHECK(data->IsNumber());
3840 CHECK_EQ(1337, data->Int32Value());
3841 CHECK(!message->IsSharedCrossOrigin());
3842 message_received = true;
3846 TEST(MessageHandler1) {
3847 message_received = false;
3848 v8::HandleScope scope(CcTest::isolate());
3849 CHECK(!message_received);
3850 v8::V8::AddMessageListener(check_message_1);
3851 LocalContext context;
3852 CompileRun("throw 1337;");
3853 CHECK(message_received);
3854 // clear out the message listener
3855 v8::V8::RemoveMessageListeners(check_message_1);
3859 static void check_message_2(v8::Handle<v8::Message> message,
3860 v8::Handle<Value> data) {
3861 LocalContext context;
3862 CHECK(data->IsObject());
3863 v8::Local<v8::Value> hidden_property =
3864 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
3865 CHECK(v8_str("hidden value")->Equals(hidden_property));
3866 CHECK(!message->IsSharedCrossOrigin());
3867 message_received = true;
3871 TEST(MessageHandler2) {
3872 message_received = false;
3873 v8::HandleScope scope(CcTest::isolate());
3874 CHECK(!message_received);
3875 v8::V8::AddMessageListener(check_message_2);
3876 LocalContext context;
3877 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
3878 v8::Object::Cast(*error)
3879 ->SetHiddenValue(v8_str("hidden key"), v8_str("hidden value"));
3880 context->Global()->Set(v8_str("error"), error);
3881 CompileRun("throw error;");
3882 CHECK(message_received);
3883 // clear out the message listener
3884 v8::V8::RemoveMessageListeners(check_message_2);
3888 static void check_message_3(v8::Handle<v8::Message> message,
3889 v8::Handle<Value> data) {
3890 CHECK(message->IsSharedCrossOrigin());
3891 CHECK(message->GetScriptOrigin().ResourceIsSharedCrossOrigin()->Value());
3892 CHECK(message->GetScriptOrigin().ResourceIsEmbedderDebugScript()->Value());
3893 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
3894 message_received = true;
3898 TEST(MessageHandler3) {
3899 message_received = false;
3900 v8::Isolate* isolate = CcTest::isolate();
3901 v8::HandleScope scope(isolate);
3902 CHECK(!message_received);
3903 v8::V8::AddMessageListener(check_message_3);
3904 LocalContext context;
3905 v8::ScriptOrigin origin =
3906 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
3907 v8::Integer::New(isolate, 2), v8::True(isolate),
3908 Handle<v8::Integer>(), v8::True(isolate));
3909 v8::Handle<v8::Script> script =
3910 Script::Compile(v8_str("throw 'error'"), &origin);
3912 CHECK(message_received);
3913 // clear out the message listener
3914 v8::V8::RemoveMessageListeners(check_message_3);
3918 static void check_message_4(v8::Handle<v8::Message> message,
3919 v8::Handle<Value> data) {
3920 CHECK(!message->IsSharedCrossOrigin());
3921 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
3922 message_received = true;
3926 TEST(MessageHandler4) {
3927 message_received = false;
3928 v8::Isolate* isolate = CcTest::isolate();
3929 v8::HandleScope scope(isolate);
3930 CHECK(!message_received);
3931 v8::V8::AddMessageListener(check_message_4);
3932 LocalContext context;
3933 v8::ScriptOrigin origin =
3934 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
3935 v8::Integer::New(isolate, 2), v8::False(isolate));
3936 v8::Handle<v8::Script> script =
3937 Script::Compile(v8_str("throw 'error'"), &origin);
3939 CHECK(message_received);
3940 // clear out the message listener
3941 v8::V8::RemoveMessageListeners(check_message_4);
3945 static void check_message_5a(v8::Handle<v8::Message> message,
3946 v8::Handle<Value> data) {
3947 CHECK(message->IsSharedCrossOrigin());
3948 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
3949 message_received = true;
3953 static void check_message_5b(v8::Handle<v8::Message> message,
3954 v8::Handle<Value> data) {
3955 CHECK(!message->IsSharedCrossOrigin());
3956 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
3957 message_received = true;
3961 TEST(MessageHandler5) {
3962 message_received = false;
3963 v8::Isolate* isolate = CcTest::isolate();
3964 v8::HandleScope scope(isolate);
3965 CHECK(!message_received);
3966 v8::V8::AddMessageListener(check_message_5a);
3967 LocalContext context;
3968 v8::ScriptOrigin origin =
3969 v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
3970 v8::Integer::New(isolate, 2), v8::True(isolate));
3971 v8::Handle<v8::Script> script =
3972 Script::Compile(v8_str("throw 'error'"), &origin);
3974 CHECK(message_received);
3975 // clear out the message listener
3976 v8::V8::RemoveMessageListeners(check_message_5a);
3978 message_received = false;
3979 v8::V8::AddMessageListener(check_message_5b);
3980 origin = v8::ScriptOrigin(v8_str("6.75"), v8::Integer::New(isolate, 1),
3981 v8::Integer::New(isolate, 2), v8::False(isolate));
3982 script = Script::Compile(v8_str("throw 'error'"), &origin);
3984 CHECK(message_received);
3985 // clear out the message listener
3986 v8::V8::RemoveMessageListeners(check_message_5b);
3990 TEST(NativeWeakMap) {
3991 v8::Isolate* isolate = CcTest::isolate();
3992 HandleScope scope(isolate);
3993 Local<v8::NativeWeakMap> weak_map(v8::NativeWeakMap::New(isolate));
3994 CHECK(!weak_map.IsEmpty());
3997 Local<Object> value = v8::Object::New(isolate);
3999 Local<Object> local1 = v8::Object::New(isolate);
4000 CHECK(!weak_map->Has(local1));
4001 CHECK(weak_map->Get(local1)->IsUndefined());
4002 weak_map->Set(local1, value);
4003 CHECK(weak_map->Has(local1));
4004 CHECK(value->Equals(weak_map->Get(local1)));
4006 WeakCallCounter counter(1234);
4007 WeakCallCounterAndPersistent<Value> o1(&counter);
4008 WeakCallCounterAndPersistent<Value> o2(&counter);
4009 WeakCallCounterAndPersistent<Value> s1(&counter);
4011 HandleScope scope(isolate);
4012 Local<v8::Object> obj1 = v8::Object::New(isolate);
4013 Local<v8::Object> obj2 = v8::Object::New(isolate);
4014 Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
4016 weak_map->Set(obj1, value);
4017 weak_map->Set(obj2, value);
4018 weak_map->Set(sym1, value);
4020 o1.handle.Reset(isolate, obj1);
4021 o2.handle.Reset(isolate, obj2);
4022 s1.handle.Reset(isolate, sym1);
4024 CHECK(weak_map->Has(local1));
4025 CHECK(weak_map->Has(obj1));
4026 CHECK(weak_map->Has(obj2));
4027 CHECK(weak_map->Has(sym1));
4029 CHECK(value->Equals(weak_map->Get(local1)));
4030 CHECK(value->Equals(weak_map->Get(obj1)));
4031 CHECK(value->Equals(weak_map->Get(obj2)));
4032 CHECK(value->Equals(weak_map->Get(sym1)));
4034 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
4036 HandleScope scope(isolate);
4037 CHECK(value->Equals(weak_map->Get(local1)));
4038 CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, o1.handle))));
4039 CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, o2.handle))));
4040 CHECK(value->Equals(weak_map->Get(Local<Value>::New(isolate, s1.handle))));
4043 o1.handle.SetWeak(&o1, &WeakPointerCallback);
4044 o2.handle.SetWeak(&o2, &WeakPointerCallback);
4045 s1.handle.SetWeak(&s1, &WeakPointerCallback);
4047 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
4048 CHECK_EQ(3, counter.NumberOfWeakCalls());
4050 CHECK(o1.handle.IsEmpty());
4051 CHECK(o2.handle.IsEmpty());
4052 CHECK(s1.handle.IsEmpty());
4054 CHECK(value->Equals(weak_map->Get(local1)));
4055 CHECK(weak_map->Delete(local1));
4056 CHECK(!weak_map->Has(local1));
4057 CHECK(weak_map->Get(local1)->IsUndefined());
4061 THREADED_TEST(GetSetProperty) {
4062 LocalContext context;
4063 v8::Isolate* isolate = context->GetIsolate();
4064 v8::HandleScope scope(isolate);
4065 context->Global()->Set(v8_str("foo"), v8_num(14));
4066 context->Global()->Set(v8_str("12"), v8_num(92));
4067 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4068 context->Global()->Set(v8_num(13), v8_num(56));
4069 Local<Value> foo = CompileRun("this.foo");
4070 CHECK_EQ(14, foo->Int32Value());
4071 Local<Value> twelve = CompileRun("this[12]");
4072 CHECK_EQ(92, twelve->Int32Value());
4073 Local<Value> sixteen = CompileRun("this[16]");
4074 CHECK_EQ(32, sixteen->Int32Value());
4075 Local<Value> thirteen = CompileRun("this[13]");
4076 CHECK_EQ(56, thirteen->Int32Value());
4078 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4079 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4080 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4082 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4083 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4084 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4086 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4087 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4088 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4092 THREADED_TEST(PropertyAttributes) {
4093 LocalContext context;
4094 v8::HandleScope scope(context->GetIsolate());
4096 Local<String> prop = v8_str("none");
4097 context->Global()->Set(prop, v8_num(7));
4098 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4100 prop = v8_str("read_only");
4101 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4102 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4103 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4104 CompileRun("read_only = 9");
4105 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4106 context->Global()->Set(prop, v8_num(10));
4107 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4109 prop = v8_str("dont_delete");
4110 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4111 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4112 CompileRun("delete dont_delete");
4113 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4114 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4116 prop = v8_str("dont_enum");
4117 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4118 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4120 prop = v8_str("absent");
4121 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4122 Local<Value> fake_prop = v8_num(1);
4123 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4126 Local<Value> exception =
4127 CompileRun("({ toString: function() { throw 'exception';} })");
4128 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4129 CHECK(try_catch.HasCaught());
4130 String::Utf8Value exception_value(try_catch.Exception());
4131 CHECK_EQ(0, strcmp("exception", *exception_value));
4136 THREADED_TEST(Array) {
4137 LocalContext context;
4138 v8::HandleScope scope(context->GetIsolate());
4139 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4140 CHECK_EQ(0u, array->Length());
4141 CHECK(array->Get(0)->IsUndefined());
4142 CHECK(!array->Has(0));
4143 CHECK(array->Get(100)->IsUndefined());
4144 CHECK(!array->Has(100));
4145 array->Set(2, v8_num(7));
4146 CHECK_EQ(3u, array->Length());
4147 CHECK(!array->Has(0));
4148 CHECK(!array->Has(1));
4149 CHECK(array->Has(2));
4150 CHECK_EQ(7, array->Get(2)->Int32Value());
4151 Local<Value> obj = CompileRun("[1, 2, 3]");
4152 Local<v8::Array> arr = obj.As<v8::Array>();
4153 CHECK_EQ(3u, arr->Length());
4154 CHECK_EQ(1, arr->Get(0)->Int32Value());
4155 CHECK_EQ(2, arr->Get(1)->Int32Value());
4156 CHECK_EQ(3, arr->Get(2)->Int32Value());
4157 array = v8::Array::New(context->GetIsolate(), 27);
4158 CHECK_EQ(27u, array->Length());
4159 array = v8::Array::New(context->GetIsolate(), -27);
4160 CHECK_EQ(0u, array->Length());
4164 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4165 v8::EscapableHandleScope scope(args.GetIsolate());
4166 ApiTestFuzzer::Fuzz();
4167 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4168 for (int i = 0; i < args.Length(); i++) result->Set(i, args[i]);
4169 args.GetReturnValue().Set(scope.Escape(result));
4173 THREADED_TEST(Vector) {
4174 v8::Isolate* isolate = CcTest::isolate();
4175 v8::HandleScope scope(isolate);
4176 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4177 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4178 LocalContext context(0, global);
4180 const char* fun = "f()";
4181 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4182 CHECK_EQ(0u, a0->Length());
4184 const char* fun2 = "f(11)";
4185 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4186 CHECK_EQ(1u, a1->Length());
4187 CHECK_EQ(11, a1->Get(0)->Int32Value());
4189 const char* fun3 = "f(12, 13)";
4190 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4191 CHECK_EQ(2u, a2->Length());
4192 CHECK_EQ(12, a2->Get(0)->Int32Value());
4193 CHECK_EQ(13, a2->Get(1)->Int32Value());
4195 const char* fun4 = "f(14, 15, 16)";
4196 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4197 CHECK_EQ(3u, a3->Length());
4198 CHECK_EQ(14, a3->Get(0)->Int32Value());
4199 CHECK_EQ(15, a3->Get(1)->Int32Value());
4200 CHECK_EQ(16, a3->Get(2)->Int32Value());
4202 const char* fun5 = "f(17, 18, 19, 20)";
4203 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4204 CHECK_EQ(4u, a4->Length());
4205 CHECK_EQ(17, a4->Get(0)->Int32Value());
4206 CHECK_EQ(18, a4->Get(1)->Int32Value());
4207 CHECK_EQ(19, a4->Get(2)->Int32Value());
4208 CHECK_EQ(20, a4->Get(3)->Int32Value());
4212 THREADED_TEST(FunctionCall) {
4213 LocalContext context;
4214 v8::Isolate* isolate = context->GetIsolate();
4215 v8::HandleScope scope(isolate);
4219 " for (var i = 0; i < arguments.length; i++) {"
4220 " result.push(arguments[i]);"
4224 "function ReturnThisSloppy() {"
4227 "function ReturnThisStrict() {"
4231 Local<Function> Foo =
4232 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4233 Local<Function> ReturnThisSloppy =
4234 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4235 Local<Function> ReturnThisStrict =
4236 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4238 v8::Handle<Value>* args0 = NULL;
4239 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4240 CHECK_EQ(0u, a0->Length());
4242 v8::Handle<Value> args1[] = {v8_num(1.1)};
4243 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4244 CHECK_EQ(1u, a1->Length());
4245 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4247 v8::Handle<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
4248 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4249 CHECK_EQ(2u, a2->Length());
4250 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4251 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4253 v8::Handle<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
4254 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4255 CHECK_EQ(3u, a3->Length());
4256 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4257 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4258 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4260 v8::Handle<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
4262 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4263 CHECK_EQ(4u, a4->Length());
4264 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4265 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4266 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4267 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4269 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4270 CHECK(r1->StrictEquals(context->Global()));
4271 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4272 CHECK(r2->StrictEquals(context->Global()));
4273 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4274 CHECK(r3->IsNumberObject());
4275 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4276 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4277 CHECK(r4->IsStringObject());
4278 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4279 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4280 CHECK(r5->IsBooleanObject());
4281 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4283 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4284 CHECK(r6->IsUndefined());
4285 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4286 CHECK(r7->IsNull());
4287 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4288 CHECK(r8->StrictEquals(v8_num(42)));
4289 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4290 CHECK(r9->StrictEquals(v8_str("hello")));
4291 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4292 CHECK(r10->StrictEquals(v8::True(isolate)));
4296 THREADED_TEST(ConstructCall) {
4297 LocalContext context;
4298 v8::Isolate* isolate = context->GetIsolate();
4299 v8::HandleScope scope(isolate);
4303 " for (var i = 0; i < arguments.length; i++) {"
4304 " result.push(arguments[i]);"
4308 Local<Function> Foo =
4309 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4311 v8::Handle<Value>* args0 = NULL;
4312 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4313 CHECK_EQ(0u, a0->Length());
4315 v8::Handle<Value> args1[] = {v8_num(1.1)};
4316 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4317 CHECK_EQ(1u, a1->Length());
4318 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4320 v8::Handle<Value> args2[] = {v8_num(2.2), v8_num(3.3)};
4321 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4322 CHECK_EQ(2u, a2->Length());
4323 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4324 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4326 v8::Handle<Value> args3[] = {v8_num(4.4), v8_num(5.5), v8_num(6.6)};
4327 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4328 CHECK_EQ(3u, a3->Length());
4329 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4330 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4331 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4333 v8::Handle<Value> args4[] = {v8_num(7.7), v8_num(8.8), v8_num(9.9),
4335 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4336 CHECK_EQ(4u, a4->Length());
4337 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4338 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4339 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4340 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4344 static void CheckUncle(v8::TryCatch* try_catch) {
4345 CHECK(try_catch->HasCaught());
4346 String::Utf8Value str_value(try_catch->Exception());
4347 CHECK_EQ(0, strcmp(*str_value, "uncle?"));
4352 THREADED_TEST(ConversionNumber) {
4354 v8::Isolate* isolate = env->GetIsolate();
4355 v8::HandleScope scope(isolate);
4356 // Very large number.
4357 CompileRun("var obj = Math.pow(2,32) * 1237;");
4358 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4359 CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
4360 CHECK_EQ(0, obj->ToInt32(isolate)->Value());
4362 obj->ToUint32(isolate)->Value()); // NOLINT - no CHECK_EQ for unsigned.
4364 CompileRun("var obj = -1234567890123;");
4365 obj = env->Global()->Get(v8_str("obj"));
4366 CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
4367 CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
4368 CHECK(2382691125u == obj->ToUint32(isolate)->Value()); // NOLINT
4369 // Small positive integer.
4370 CompileRun("var obj = 42;");
4371 obj = env->Global()->Get(v8_str("obj"));
4372 CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
4373 CHECK_EQ(42, obj->ToInt32(isolate)->Value());
4374 CHECK(42u == obj->ToUint32(isolate)->Value()); // NOLINT
4375 // Negative integer.
4376 CompileRun("var obj = -37;");
4377 obj = env->Global()->Get(v8_str("obj"));
4378 CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
4379 CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
4380 CHECK(4294967259u == obj->ToUint32(isolate)->Value()); // NOLINT
4381 // Positive non-int32 integer.
4382 CompileRun("var obj = 0x81234567;");
4383 obj = env->Global()->Get(v8_str("obj"));
4384 CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
4385 CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
4386 CHECK(2166572391u == obj->ToUint32(isolate)->Value()); // NOLINT
4388 CompileRun("var obj = 42.3;");
4389 obj = env->Global()->Get(v8_str("obj"));
4390 CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
4391 CHECK_EQ(42, obj->ToInt32(isolate)->Value());
4392 CHECK(42u == obj->ToUint32(isolate)->Value()); // NOLINT
4393 // Large negative fraction.
4394 CompileRun("var obj = -5726623061.75;");
4395 obj = env->Global()->Get(v8_str("obj"));
4396 CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
4397 CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
4398 CHECK(2863311531u == obj->ToUint32(isolate)->Value()); // NOLINT
4402 THREADED_TEST(isNumberType) {
4404 v8::HandleScope scope(env->GetIsolate());
4405 // Very large number.
4406 CompileRun("var obj = Math.pow(2,32) * 1237;");
4407 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4408 CHECK(!obj->IsInt32());
4409 CHECK(!obj->IsUint32());
4410 // Large negative number.
4411 CompileRun("var obj = -1234567890123;");
4412 obj = env->Global()->Get(v8_str("obj"));
4413 CHECK(!obj->IsInt32());
4414 CHECK(!obj->IsUint32());
4415 // Small positive integer.
4416 CompileRun("var obj = 42;");
4417 obj = env->Global()->Get(v8_str("obj"));
4418 CHECK(obj->IsInt32());
4419 CHECK(obj->IsUint32());
4420 // Negative integer.
4421 CompileRun("var obj = -37;");
4422 obj = env->Global()->Get(v8_str("obj"));
4423 CHECK(obj->IsInt32());
4424 CHECK(!obj->IsUint32());
4425 // Positive non-int32 integer.
4426 CompileRun("var obj = 0x81234567;");
4427 obj = env->Global()->Get(v8_str("obj"));
4428 CHECK(!obj->IsInt32());
4429 CHECK(obj->IsUint32());
4431 CompileRun("var obj = 42.3;");
4432 obj = env->Global()->Get(v8_str("obj"));
4433 CHECK(!obj->IsInt32());
4434 CHECK(!obj->IsUint32());
4435 // Large negative fraction.
4436 CompileRun("var obj = -5726623061.75;");
4437 obj = env->Global()->Get(v8_str("obj"));
4438 CHECK(!obj->IsInt32());
4439 CHECK(!obj->IsUint32());
4441 CompileRun("var obj = 0.0;");
4442 obj = env->Global()->Get(v8_str("obj"));
4443 CHECK(obj->IsInt32());
4444 CHECK(obj->IsUint32());
4446 CompileRun("var obj = -0.0;");
4447 obj = env->Global()->Get(v8_str("obj"));
4448 CHECK(!obj->IsInt32());
4449 CHECK(!obj->IsUint32());
4453 THREADED_TEST(ConversionException) {
4455 v8::Isolate* isolate = env->GetIsolate();
4456 v8::HandleScope scope(isolate);
4458 "function TestClass() { };"
4459 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4460 "var obj = new TestClass();");
4461 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4463 v8::TryCatch try_catch(isolate);
4465 Local<Value> to_string_result = obj->ToString(isolate);
4466 CHECK(to_string_result.IsEmpty());
4467 CheckUncle(&try_catch);
4469 Local<Value> to_number_result = obj->ToNumber(isolate);
4470 CHECK(to_number_result.IsEmpty());
4471 CheckUncle(&try_catch);
4473 Local<Value> to_integer_result = obj->ToInteger(isolate);
4474 CHECK(to_integer_result.IsEmpty());
4475 CheckUncle(&try_catch);
4477 Local<Value> to_uint32_result = obj->ToUint32(isolate);
4478 CHECK(to_uint32_result.IsEmpty());
4479 CheckUncle(&try_catch);
4481 Local<Value> to_int32_result = obj->ToInt32(isolate);
4482 CHECK(to_int32_result.IsEmpty());
4483 CheckUncle(&try_catch);
4485 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
4486 CHECK(to_object_result.IsEmpty());
4487 CHECK(try_catch.HasCaught());
4490 int32_t int32_value = obj->Int32Value();
4491 CHECK_EQ(0, int32_value);
4492 CheckUncle(&try_catch);
4494 uint32_t uint32_value = obj->Uint32Value();
4495 CHECK_EQ(0u, uint32_value);
4496 CheckUncle(&try_catch);
4498 double number_value = obj->NumberValue();
4499 CHECK(std::isnan(number_value));
4500 CheckUncle(&try_catch);
4502 int64_t integer_value = obj->IntegerValue();
4503 CHECK_EQ(0, integer_value);
4504 CheckUncle(&try_catch);
4508 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
4509 ApiTestFuzzer::Fuzz();
4510 args.GetIsolate()->ThrowException(v8_str("konto"));
4514 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
4515 if (args.Length() < 1) {
4516 args.GetReturnValue().Set(false);
4519 v8::HandleScope scope(args.GetIsolate());
4520 v8::TryCatch try_catch;
4521 Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
4522 CHECK(!try_catch.HasCaught() || result.IsEmpty());
4523 args.GetReturnValue().Set(try_catch.HasCaught());
4527 THREADED_TEST(APICatch) {
4528 v8::Isolate* isolate = CcTest::isolate();
4529 v8::HandleScope scope(isolate);
4530 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4531 templ->Set(v8_str("ThrowFromC"),
4532 v8::FunctionTemplate::New(isolate, ThrowFromC));
4533 LocalContext context(0, templ);
4535 "var thrown = false;"
4541 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
4542 CHECK(thrown->BooleanValue());
4546 THREADED_TEST(APIThrowTryCatch) {
4547 v8::Isolate* isolate = CcTest::isolate();
4548 v8::HandleScope scope(isolate);
4549 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4550 templ->Set(v8_str("ThrowFromC"),
4551 v8::FunctionTemplate::New(isolate, ThrowFromC));
4552 LocalContext context(0, templ);
4553 v8::TryCatch try_catch;
4554 CompileRun("ThrowFromC();");
4555 CHECK(try_catch.HasCaught());
4559 // Test that a try-finally block doesn't shadow a try-catch block
4560 // when setting up an external handler.
4562 // BUG(271): Some of the exception propagation does not work on the
4563 // ARM simulator because the simulator separates the C++ stack and the
4564 // JS stack. This test therefore fails on the simulator. The test is
4565 // not threaded to allow the threading tests to run on the simulator.
4566 TEST(TryCatchInTryFinally) {
4567 v8::Isolate* isolate = CcTest::isolate();
4568 v8::HandleScope scope(isolate);
4569 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4570 templ->Set(v8_str("CCatcher"), v8::FunctionTemplate::New(isolate, CCatcher));
4571 LocalContext context(0, templ);
4572 Local<Value> result = CompileRun(
4575 " CCatcher('throw 7;');"
4580 CHECK(result->IsTrue());
4584 static void check_reference_error_message(v8::Handle<v8::Message> message,
4585 v8::Handle<v8::Value> data) {
4586 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
4587 CHECK(message->Get()->Equals(v8_str(reference_error)));
4591 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
4592 ApiTestFuzzer::Fuzz();
4597 // Test that overwritten methods are not invoked on uncaught exception
4598 // formatting. However, they are invoked when performing normal error
4599 // string conversions.
4600 TEST(APIThrowMessageOverwrittenToString) {
4601 v8::Isolate* isolate = CcTest::isolate();
4602 v8::HandleScope scope(isolate);
4603 v8::V8::AddMessageListener(check_reference_error_message);
4604 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4605 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
4606 LocalContext context(NULL, templ);
4607 CompileRun("asdf;");
4610 "limit.valueOf = fail;"
4611 "Error.stackTraceLimit = limit;");
4613 CompileRun("Array.prototype.pop = fail;");
4614 CompileRun("Object.prototype.hasOwnProperty = fail;");
4615 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
4616 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
4617 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
4619 "ReferenceError.prototype.toString ="
4620 " function() { return 'Whoops' }");
4621 CompileRun("asdf;");
4622 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
4623 CompileRun("asdf;");
4624 CompileRun("ReferenceError.prototype.constructor = void 0;");
4625 CompileRun("asdf;");
4626 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
4627 CompileRun("asdf;");
4628 CompileRun("ReferenceError.prototype = new Object();");
4629 CompileRun("asdf;");
4630 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
4631 CHECK(string->Equals(v8_str("Whoops")));
4633 "ReferenceError.prototype.constructor = new Object();"
4634 "ReferenceError.prototype.constructor.name = 1;"
4635 "Number.prototype.toString = function() { return 'Whoops'; };"
4636 "ReferenceError.prototype.toString = Object.prototype.toString;");
4637 CompileRun("asdf;");
4638 v8::V8::RemoveMessageListeners(check_reference_error_message);
4642 static void check_custom_error_tostring(v8::Handle<v8::Message> message,
4643 v8::Handle<v8::Value> data) {
4644 const char* uncaught_error = "Uncaught MyError toString";
4645 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4649 TEST(CustomErrorToString) {
4650 LocalContext context;
4651 v8::HandleScope scope(context->GetIsolate());
4652 v8::V8::AddMessageListener(check_custom_error_tostring);
4654 "function MyError(name, message) { "
4655 " this.name = name; "
4656 " this.message = message; "
4658 "MyError.prototype = Object.create(Error.prototype); "
4659 "MyError.prototype.toString = function() { "
4660 " return 'MyError toString'; "
4662 "throw new MyError('my name', 'my message'); ");
4663 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
4667 static void check_custom_error_message(v8::Handle<v8::Message> message,
4668 v8::Handle<v8::Value> data) {
4669 const char* uncaught_error = "Uncaught MyError: my message";
4670 printf("%s\n", *v8::String::Utf8Value(message->Get()));
4671 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
4675 TEST(CustomErrorMessage) {
4676 LocalContext context;
4677 v8::HandleScope scope(context->GetIsolate());
4678 v8::V8::AddMessageListener(check_custom_error_message);
4682 "function MyError(msg) { "
4683 " this.name = 'MyError'; "
4684 " this.message = msg; "
4686 "MyError.prototype = new Error(); "
4687 "throw new MyError('my message'); ");
4691 "function MyError(msg) { "
4692 " this.name = 'MyError'; "
4693 " this.message = msg; "
4695 "inherits = function(childCtor, parentCtor) { "
4696 " function tempCtor() {}; "
4697 " tempCtor.prototype = parentCtor.prototype; "
4698 " childCtor.superClass_ = parentCtor.prototype; "
4699 " childCtor.prototype = new tempCtor(); "
4700 " childCtor.prototype.constructor = childCtor; "
4702 "inherits(MyError, Error); "
4703 "throw new MyError('my message'); ");
4707 "function MyError(msg) { "
4708 " this.name = 'MyError'; "
4709 " this.message = msg; "
4711 "MyError.prototype = Object.create(Error.prototype); "
4712 "throw new MyError('my message'); ");
4714 v8::V8::RemoveMessageListeners(check_custom_error_message);
4718 static void receive_message(v8::Handle<v8::Message> message,
4719 v8::Handle<v8::Value> data) {
4721 message_received = true;
4725 TEST(APIThrowMessage) {
4726 message_received = false;
4727 v8::Isolate* isolate = CcTest::isolate();
4728 v8::HandleScope scope(isolate);
4729 v8::V8::AddMessageListener(receive_message);
4730 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4731 templ->Set(v8_str("ThrowFromC"),
4732 v8::FunctionTemplate::New(isolate, ThrowFromC));
4733 LocalContext context(0, templ);
4734 CompileRun("ThrowFromC();");
4735 CHECK(message_received);
4736 v8::V8::RemoveMessageListeners(receive_message);
4740 TEST(APIThrowMessageAndVerboseTryCatch) {
4741 message_received = false;
4742 v8::Isolate* isolate = CcTest::isolate();
4743 v8::HandleScope scope(isolate);
4744 v8::V8::AddMessageListener(receive_message);
4745 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4746 templ->Set(v8_str("ThrowFromC"),
4747 v8::FunctionTemplate::New(isolate, ThrowFromC));
4748 LocalContext context(0, templ);
4749 v8::TryCatch try_catch;
4750 try_catch.SetVerbose(true);
4751 Local<Value> result = CompileRun("ThrowFromC();");
4752 CHECK(try_catch.HasCaught());
4753 CHECK(result.IsEmpty());
4754 CHECK(message_received);
4755 v8::V8::RemoveMessageListeners(receive_message);
4759 TEST(APIStackOverflowAndVerboseTryCatch) {
4760 message_received = false;
4761 LocalContext context;
4762 v8::HandleScope scope(context->GetIsolate());
4763 v8::V8::AddMessageListener(receive_message);
4764 v8::TryCatch try_catch;
4765 try_catch.SetVerbose(true);
4766 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
4767 CHECK(try_catch.HasCaught());
4768 CHECK(result.IsEmpty());
4769 CHECK(message_received);
4770 v8::V8::RemoveMessageListeners(receive_message);
4774 THREADED_TEST(ExternalScriptException) {
4775 v8::Isolate* isolate = CcTest::isolate();
4776 v8::HandleScope scope(isolate);
4777 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4778 templ->Set(v8_str("ThrowFromC"),
4779 v8::FunctionTemplate::New(isolate, ThrowFromC));
4780 LocalContext context(0, templ);
4782 v8::TryCatch try_catch;
4783 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
4784 CHECK(result.IsEmpty());
4785 CHECK(try_catch.HasCaught());
4786 String::Utf8Value exception_value(try_catch.Exception());
4787 CHECK_EQ(0, strcmp("konto", *exception_value));
4791 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
4792 ApiTestFuzzer::Fuzz();
4793 CHECK_EQ(4, args.Length());
4794 int count = args[0]->Int32Value();
4795 int cInterval = args[2]->Int32Value();
4797 args.GetIsolate()->ThrowException(v8_str("FromC"));
4800 Local<v8::Object> global = args.GetIsolate()->GetCurrentContext()->Global();
4801 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
4802 v8::Handle<Value> argv[] = {v8_num(count - 1), args[1], args[2], args[3]};
4803 if (count % cInterval == 0) {
4804 v8::TryCatch try_catch;
4805 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
4806 int expected = args[3]->Int32Value();
4807 if (try_catch.HasCaught()) {
4808 CHECK_EQ(expected, count);
4809 CHECK(result.IsEmpty());
4810 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
4812 CHECK_NE(expected, count);
4814 args.GetReturnValue().Set(result);
4817 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
4824 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
4825 ApiTestFuzzer::Fuzz();
4826 CHECK_EQ(3, args.Length());
4827 bool equality = args[0]->BooleanValue();
4828 int count = args[1]->Int32Value();
4829 int expected = args[2]->Int32Value();
4831 CHECK_EQ(count, expected);
4833 CHECK_NE(count, expected);
4838 THREADED_TEST(EvalInTryFinally) {
4839 LocalContext context;
4840 v8::HandleScope scope(context->GetIsolate());
4841 v8::TryCatch try_catch;
4845 " eval('asldkf (*&^&*^');"
4850 CHECK(!try_catch.HasCaught());
4854 // This test works by making a stack of alternating JavaScript and C
4855 // activations. These activations set up exception handlers with regular
4856 // intervals, one interval for C activations and another for JavaScript
4857 // activations. When enough activations have been created an exception is
4858 // thrown and we check that the right activation catches the exception and that
4859 // no other activations do. The right activation is always the topmost one with
4860 // a handler, regardless of whether it is in JavaScript or C.
4862 // The notation used to describe a test case looks like this:
4864 // *JS[4] *C[3] @JS[2] C[1] JS[0]
4866 // Each entry is an activation, either JS or C. The index is the count at that
4867 // level. Stars identify activations with exception handlers, the @ identifies
4868 // the exception handler that should catch the exception.
4870 // BUG(271): Some of the exception propagation does not work on the
4871 // ARM simulator because the simulator separates the C++ stack and the
4872 // JS stack. This test therefore fails on the simulator. The test is
4873 // not threaded to allow the threading tests to run on the simulator.
4874 TEST(ExceptionOrder) {
4875 v8::Isolate* isolate = CcTest::isolate();
4876 v8::HandleScope scope(isolate);
4877 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4878 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
4879 templ->Set(v8_str("CThrowCountDown"),
4880 v8::FunctionTemplate::New(isolate, CThrowCountDown));
4881 LocalContext context(0, templ);
4883 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
4884 " if (count == 0) throw 'FromJS';"
4885 " if (count % jsInterval == 0) {"
4887 " var value = CThrowCountDown(count - 1,"
4891 " check(false, count, expected);"
4894 " check(true, count, expected);"
4897 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
4900 Local<Function> fun =
4901 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
4904 // count jsInterval cInterval expected
4906 // *JS[4] *C[3] @JS[2] C[1] JS[0]
4907 v8::Handle<Value> a0[argc] = {v8_num(4), v8_num(2), v8_num(3), v8_num(2)};
4908 fun->Call(fun, argc, a0);
4910 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
4911 v8::Handle<Value> a1[argc] = {v8_num(5), v8_num(6), v8_num(1), v8_num(2)};
4912 fun->Call(fun, argc, a1);
4914 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
4915 v8::Handle<Value> a2[argc] = {v8_num(6), v8_num(7), v8_num(5), v8_num(5)};
4916 fun->Call(fun, argc, a2);
4918 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
4919 v8::Handle<Value> a3[argc] = {v8_num(6), v8_num(6), v8_num(7), v8_num(6)};
4920 fun->Call(fun, argc, a3);
4922 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
4923 v8::Handle<Value> a4[argc] = {v8_num(6), v8_num(4), v8_num(5), v8_num(4)};
4924 fun->Call(fun, argc, a4);
4926 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
4927 v8::Handle<Value> a5[argc] = {v8_num(6), v8_num(4), v8_num(3), v8_num(3)};
4928 fun->Call(fun, argc, a5);
4932 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
4933 ApiTestFuzzer::Fuzz();
4934 CHECK_EQ(1, args.Length());
4935 args.GetIsolate()->ThrowException(args[0]);
4939 THREADED_TEST(ThrowValues) {
4940 v8::Isolate* isolate = CcTest::isolate();
4941 v8::HandleScope scope(isolate);
4942 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
4943 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
4944 LocalContext context(0, templ);
4945 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
4946 "function Run(obj) {"
4952 " return 'no exception';"
4954 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
4955 CHECK_EQ(5u, result->Length());
4956 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
4957 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
4958 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
4959 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
4960 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
4961 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
4962 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
4966 THREADED_TEST(CatchZero) {
4967 LocalContext context;
4968 v8::HandleScope scope(context->GetIsolate());
4969 v8::TryCatch try_catch;
4970 CHECK(!try_catch.HasCaught());
4971 CompileRun("throw 10");
4972 CHECK(try_catch.HasCaught());
4973 CHECK_EQ(10, try_catch.Exception()->Int32Value());
4975 CHECK(!try_catch.HasCaught());
4976 CompileRun("throw 0");
4977 CHECK(try_catch.HasCaught());
4978 CHECK_EQ(0, try_catch.Exception()->Int32Value());
4982 THREADED_TEST(CatchExceptionFromWith) {
4983 LocalContext context;
4984 v8::HandleScope scope(context->GetIsolate());
4985 v8::TryCatch try_catch;
4986 CHECK(!try_catch.HasCaught());
4987 CompileRun("var o = {}; with (o) { throw 42; }");
4988 CHECK(try_catch.HasCaught());
4992 THREADED_TEST(TryCatchAndFinallyHidingException) {
4993 LocalContext context;
4994 v8::HandleScope scope(context->GetIsolate());
4995 v8::TryCatch try_catch;
4996 CHECK(!try_catch.HasCaught());
4997 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
4998 CompileRun("f({toString: function() { throw 42; }});");
4999 CHECK(!try_catch.HasCaught());
5003 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5004 v8::TryCatch try_catch;
5008 THREADED_TEST(TryCatchAndFinally) {
5009 LocalContext context;
5010 v8::Isolate* isolate = context->GetIsolate();
5011 v8::HandleScope scope(isolate);
5012 context->Global()->Set(
5013 v8_str("native_with_try_catch"),
5014 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5015 v8::TryCatch try_catch;
5016 CHECK(!try_catch.HasCaught());
5019 " throw new Error('a');\n"
5021 " native_with_try_catch();\n"
5023 CHECK(try_catch.HasCaught());
5027 static void TryCatchNested1Helper(int depth) {
5029 v8::TryCatch try_catch;
5030 try_catch.SetVerbose(true);
5031 TryCatchNested1Helper(depth - 1);
5032 CHECK(try_catch.HasCaught());
5033 try_catch.ReThrow();
5035 CcTest::isolate()->ThrowException(v8_str("E1"));
5040 static void TryCatchNested2Helper(int depth) {
5042 v8::TryCatch try_catch;
5043 try_catch.SetVerbose(true);
5044 TryCatchNested2Helper(depth - 1);
5045 CHECK(try_catch.HasCaught());
5046 try_catch.ReThrow();
5048 CompileRun("throw 'E2';");
5053 TEST(TryCatchNested) {
5054 v8::V8::Initialize();
5055 LocalContext context;
5056 v8::HandleScope scope(context->GetIsolate());
5059 // Test nested try-catch with a native throw in the end.
5060 v8::TryCatch try_catch;
5061 TryCatchNested1Helper(5);
5062 CHECK(try_catch.HasCaught());
5063 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5067 // Test nested try-catch with a JavaScript throw in the end.
5068 v8::TryCatch try_catch;
5069 TryCatchNested2Helper(5);
5070 CHECK(try_catch.HasCaught());
5071 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5076 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5077 CHECK(try_catch->HasCaught());
5078 Handle<Message> message = try_catch->Message();
5079 Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5080 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5082 strcmp(*v8::String::Utf8Value(message->Get()), "Uncaught Error: a"));
5083 CHECK_EQ(1, message->GetLineNumber());
5084 CHECK_EQ(6, message->GetStartColumn());
5088 void TryCatchMixedNestingHelper(
5089 const v8::FunctionCallbackInfo<v8::Value>& args) {
5090 ApiTestFuzzer::Fuzz();
5091 v8::TryCatch try_catch;
5092 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5093 CHECK(try_catch.HasCaught());
5094 TryCatchMixedNestingCheck(&try_catch);
5095 try_catch.ReThrow();
5099 // This test ensures that an outer TryCatch in the following situation:
5100 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5101 // does not clobber the Message object generated for the inner TryCatch.
5102 // This exercises the ability of TryCatch.ReThrow() to restore the
5103 // inner pending Message before throwing the exception again.
5104 TEST(TryCatchMixedNesting) {
5105 v8::Isolate* isolate = CcTest::isolate();
5106 v8::HandleScope scope(isolate);
5107 v8::V8::Initialize();
5108 v8::TryCatch try_catch;
5109 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5110 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5111 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5112 LocalContext context(0, templ);
5113 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5114 TryCatchMixedNestingCheck(&try_catch);
5118 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5119 ApiTestFuzzer::Fuzz();
5120 v8::TryCatch try_catch;
5121 args.GetIsolate()->ThrowException(v8_str("boom"));
5122 CHECK(try_catch.HasCaught());
5126 TEST(TryCatchNative) {
5127 v8::Isolate* isolate = CcTest::isolate();
5128 v8::HandleScope scope(isolate);
5129 v8::V8::Initialize();
5130 v8::TryCatch try_catch;
5131 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5132 templ->Set(v8_str("TryCatchNativeHelper"),
5133 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5134 LocalContext context(0, templ);
5135 CompileRun("TryCatchNativeHelper();");
5136 CHECK(!try_catch.HasCaught());
5140 void TryCatchNativeResetHelper(
5141 const v8::FunctionCallbackInfo<v8::Value>& args) {
5142 ApiTestFuzzer::Fuzz();
5143 v8::TryCatch try_catch;
5144 args.GetIsolate()->ThrowException(v8_str("boom"));
5145 CHECK(try_catch.HasCaught());
5147 CHECK(!try_catch.HasCaught());
5151 TEST(TryCatchNativeReset) {
5152 v8::Isolate* isolate = CcTest::isolate();
5153 v8::HandleScope scope(isolate);
5154 v8::V8::Initialize();
5155 v8::TryCatch try_catch;
5156 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5157 templ->Set(v8_str("TryCatchNativeResetHelper"),
5158 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5159 LocalContext context(0, templ);
5160 CompileRun("TryCatchNativeResetHelper();");
5161 CHECK(!try_catch.HasCaught());
5165 THREADED_TEST(Equality) {
5166 LocalContext context;
5167 v8::Isolate* isolate = context->GetIsolate();
5168 v8::HandleScope scope(context->GetIsolate());
5169 // Check that equality works at all before relying on CHECK_EQ
5170 CHECK(v8_str("a")->Equals(v8_str("a")));
5171 CHECK(!v8_str("a")->Equals(v8_str("b")));
5173 CHECK(v8_str("a")->Equals(v8_str("a")));
5174 CHECK(!v8_str("a")->Equals(v8_str("b")));
5175 CHECK(v8_num(1)->Equals(v8_num(1)));
5176 CHECK(v8_num(1.00)->Equals(v8_num(1)));
5177 CHECK(!v8_num(1)->Equals(v8_num(2)));
5179 // Assume String is not internalized.
5180 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5181 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5182 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5183 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5184 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5185 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5186 Local<Value> not_a_number = v8_num(std::numeric_limits<double>::quiet_NaN());
5187 CHECK(!not_a_number->StrictEquals(not_a_number));
5188 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5189 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5191 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5192 v8::Persistent<v8::Object> alias(isolate, obj);
5193 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5196 CHECK(v8_str("a")->SameValue(v8_str("a")));
5197 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5198 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5199 CHECK(v8_num(1)->SameValue(v8_num(1)));
5200 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5201 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5202 CHECK(not_a_number->SameValue(not_a_number));
5203 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5204 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5208 THREADED_TEST(MultiRun) {
5209 LocalContext context;
5210 v8::HandleScope scope(context->GetIsolate());
5211 Local<Script> script = v8_compile("x");
5212 for (int i = 0; i < 10; i++) script->Run();
5216 static void GetXValue(Local<String> name,
5217 const v8::PropertyCallbackInfo<v8::Value>& info) {
5218 ApiTestFuzzer::Fuzz();
5219 CHECK(info.Data()->Equals(v8_str("donut")));
5220 CHECK(name->Equals(v8_str("x")));
5221 info.GetReturnValue().Set(name);
5225 THREADED_TEST(SimplePropertyRead) {
5226 LocalContext context;
5227 v8::Isolate* isolate = context->GetIsolate();
5228 v8::HandleScope scope(isolate);
5229 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5230 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5231 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5232 Local<Script> script = v8_compile("obj.x");
5233 for (int i = 0; i < 10; i++) {
5234 Local<Value> result = script->Run();
5235 CHECK(result->Equals(v8_str("x")));
5240 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5241 LocalContext context;
5242 v8::Isolate* isolate = context->GetIsolate();
5243 v8::HandleScope scope(isolate);
5244 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5245 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5246 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5248 // Uses getOwnPropertyDescriptor to check the configurable status
5249 Local<Script> script_desc = v8_compile(
5250 "var prop = Object.getOwnPropertyDescriptor( "
5252 "prop.configurable;");
5253 Local<Value> result = script_desc->Run();
5254 CHECK_EQ(result->BooleanValue(), true);
5256 // Redefine get - but still configurable
5257 Local<Script> script_define = v8_compile(
5258 "var desc = { get: function(){return 42; },"
5259 " configurable: true };"
5260 "Object.defineProperty(obj, 'x', desc);"
5262 result = script_define->Run();
5263 CHECK(result->Equals(v8_num(42)));
5265 // Check that the accessor is still configurable
5266 result = script_desc->Run();
5267 CHECK_EQ(result->BooleanValue(), true);
5269 // Redefine to a non-configurable
5270 script_define = v8_compile(
5271 "var desc = { get: function(){return 43; },"
5272 " configurable: false };"
5273 "Object.defineProperty(obj, 'x', desc);"
5275 result = script_define->Run();
5276 CHECK(result->Equals(v8_num(43)));
5277 result = script_desc->Run();
5278 CHECK_EQ(result->BooleanValue(), false);
5280 // Make sure that it is not possible to redefine again
5281 v8::TryCatch try_catch;
5282 result = script_define->Run();
5283 CHECK(try_catch.HasCaught());
5284 String::Utf8Value exception_value(try_catch.Exception());
5286 strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5290 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5291 v8::Isolate* isolate = CcTest::isolate();
5292 v8::HandleScope scope(isolate);
5293 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5294 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5295 LocalContext context;
5296 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5298 Local<Script> script_desc = v8_compile(
5300 "Object.getOwnPropertyDescriptor( "
5302 "prop.configurable;");
5303 Local<Value> result = script_desc->Run();
5304 CHECK_EQ(result->BooleanValue(), true);
5306 Local<Script> script_define = v8_compile(
5307 "var desc = {get: function(){return 42; },"
5308 " configurable: true };"
5309 "Object.defineProperty(obj, 'x', desc);"
5311 result = script_define->Run();
5312 CHECK(result->Equals(v8_num(42)));
5315 result = script_desc->Run();
5316 CHECK_EQ(result->BooleanValue(), true);
5319 script_define = v8_compile(
5320 "var desc = {get: function(){return 43; },"
5321 " configurable: false };"
5322 "Object.defineProperty(obj, 'x', desc);"
5324 result = script_define->Run();
5325 CHECK(result->Equals(v8_num(43)));
5326 result = script_desc->Run();
5328 CHECK_EQ(result->BooleanValue(), false);
5330 v8::TryCatch try_catch;
5331 result = script_define->Run();
5332 CHECK(try_catch.HasCaught());
5333 String::Utf8Value exception_value(try_catch.Exception());
5335 strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5339 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5341 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5345 THREADED_TEST(DefineAPIAccessorOnObject) {
5346 v8::Isolate* isolate = CcTest::isolate();
5347 v8::HandleScope scope(isolate);
5348 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5349 LocalContext context;
5351 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5352 CompileRun("var obj2 = {};");
5354 CHECK(CompileRun("obj1.x")->IsUndefined());
5355 CHECK(CompileRun("obj2.x")->IsUndefined());
5357 CHECK(GetGlobalProperty(&context, "obj1")
5358 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5360 ExpectString("obj1.x", "x");
5361 CHECK(CompileRun("obj2.x")->IsUndefined());
5363 CHECK(GetGlobalProperty(&context, "obj2")
5364 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5366 ExpectString("obj1.x", "x");
5367 ExpectString("obj2.x", "x");
5369 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5370 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5373 "Object.defineProperty(obj1, 'x',"
5374 "{ get: function() { return 'y'; }, configurable: true })");
5376 ExpectString("obj1.x", "y");
5377 ExpectString("obj2.x", "x");
5380 "Object.defineProperty(obj2, 'x',"
5381 "{ get: function() { return 'y'; }, configurable: true })");
5383 ExpectString("obj1.x", "y");
5384 ExpectString("obj2.x", "y");
5386 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5387 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5389 CHECK(GetGlobalProperty(&context, "obj1")
5390 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5391 CHECK(GetGlobalProperty(&context, "obj2")
5392 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5394 ExpectString("obj1.x", "x");
5395 ExpectString("obj2.x", "x");
5397 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5398 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5400 // Define getters/setters, but now make them not configurable.
5402 "Object.defineProperty(obj1, 'x',"
5403 "{ get: function() { return 'z'; }, configurable: false })");
5405 "Object.defineProperty(obj2, 'x',"
5406 "{ get: function() { return 'z'; }, configurable: false })");
5408 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5409 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5411 ExpectString("obj1.x", "z");
5412 ExpectString("obj2.x", "z");
5414 CHECK(!GetGlobalProperty(&context, "obj1")
5415 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5416 CHECK(!GetGlobalProperty(&context, "obj2")
5417 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5419 ExpectString("obj1.x", "z");
5420 ExpectString("obj2.x", "z");
5424 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5425 v8::Isolate* isolate = CcTest::isolate();
5426 v8::HandleScope scope(isolate);
5427 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5428 LocalContext context;
5430 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5431 CompileRun("var obj2 = {};");
5433 CHECK(GetGlobalProperty(&context, "obj1")
5434 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"),
5435 v8::DEFAULT, v8::DontDelete));
5436 CHECK(GetGlobalProperty(&context, "obj2")
5437 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"),
5438 v8::DEFAULT, v8::DontDelete));
5440 ExpectString("obj1.x", "x");
5441 ExpectString("obj2.x", "x");
5443 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5444 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5446 CHECK(!GetGlobalProperty(&context, "obj1")
5447 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5448 CHECK(!GetGlobalProperty(&context, "obj2")
5449 ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5452 v8::TryCatch try_catch;
5454 "Object.defineProperty(obj1, 'x',"
5455 "{get: function() { return 'func'; }})");
5456 CHECK(try_catch.HasCaught());
5457 String::Utf8Value exception_value(try_catch.Exception());
5459 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5462 v8::TryCatch try_catch;
5464 "Object.defineProperty(obj2, 'x',"
5465 "{get: function() { return 'func'; }})");
5466 CHECK(try_catch.HasCaught());
5467 String::Utf8Value exception_value(try_catch.Exception());
5469 0, strcmp(*exception_value, "TypeError: Cannot redefine property: x"));
5474 static void Get239Value(Local<String> name,
5475 const v8::PropertyCallbackInfo<v8::Value>& info) {
5476 ApiTestFuzzer::Fuzz();
5477 CHECK(info.Data()->Equals(v8_str("donut")));
5478 CHECK(name->Equals(v8_str("239")));
5479 info.GetReturnValue().Set(name);
5483 THREADED_TEST(ElementAPIAccessor) {
5484 v8::Isolate* isolate = CcTest::isolate();
5485 v8::HandleScope scope(isolate);
5486 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5487 LocalContext context;
5489 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5490 CompileRun("var obj2 = {};");
5492 CHECK(GetGlobalProperty(&context, "obj1")
5493 ->SetAccessor(v8_str("239"), Get239Value, NULL, v8_str("donut")));
5494 CHECK(GetGlobalProperty(&context, "obj2")
5495 ->SetAccessor(v8_str("239"), Get239Value, NULL, v8_str("donut")));
5497 ExpectString("obj1[239]", "239");
5498 ExpectString("obj2[239]", "239");
5499 ExpectString("obj1['239']", "239");
5500 ExpectString("obj2['239']", "239");
5504 v8::Persistent<Value> xValue;
5507 static void SetXValue(Local<String> name, Local<Value> value,
5508 const v8::PropertyCallbackInfo<void>& info) {
5509 CHECK(value->Equals(v8_num(4)));
5510 CHECK(info.Data()->Equals(v8_str("donut")));
5511 CHECK(name->Equals(v8_str("x")));
5512 CHECK(xValue.IsEmpty());
5513 xValue.Reset(info.GetIsolate(), value);
5517 THREADED_TEST(SimplePropertyWrite) {
5518 v8::Isolate* isolate = CcTest::isolate();
5519 v8::HandleScope scope(isolate);
5520 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5521 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
5522 LocalContext context;
5523 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5524 Local<Script> script = v8_compile("obj.x = 4");
5525 for (int i = 0; i < 10; i++) {
5526 CHECK(xValue.IsEmpty());
5528 CHECK(v8_num(4)->Equals(Local<Value>::New(CcTest::isolate(), xValue)));
5534 THREADED_TEST(SetterOnly) {
5535 v8::Isolate* isolate = CcTest::isolate();
5536 v8::HandleScope scope(isolate);
5537 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5538 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
5539 LocalContext context;
5540 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5541 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5542 for (int i = 0; i < 10; i++) {
5543 CHECK(xValue.IsEmpty());
5545 CHECK(v8_num(4)->Equals(Local<Value>::New(CcTest::isolate(), xValue)));
5551 THREADED_TEST(NoAccessors) {
5552 v8::Isolate* isolate = CcTest::isolate();
5553 v8::HandleScope scope(isolate);
5554 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5555 templ->SetAccessor(v8_str("x"), static_cast<v8::AccessorGetterCallback>(NULL),
5556 NULL, v8_str("donut"));
5557 LocalContext context;
5558 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5559 Local<Script> script = v8_compile("obj.x = 4; obj.x");
5560 for (int i = 0; i < 10; i++) {
5566 THREADED_TEST(MultiContexts) {
5567 v8::Isolate* isolate = CcTest::isolate();
5568 v8::HandleScope scope(isolate);
5569 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5570 templ->Set(v8_str("dummy"),
5571 v8::FunctionTemplate::New(isolate, DummyCallHandler));
5573 Local<String> password = v8_str("Password");
5575 // Create an environment
5576 LocalContext context0(0, templ);
5577 context0->SetSecurityToken(password);
5578 v8::Handle<v8::Object> global0 = context0->Global();
5579 global0->Set(v8_str("custom"), v8_num(1234));
5580 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5582 // Create an independent environment
5583 LocalContext context1(0, templ);
5584 context1->SetSecurityToken(password);
5585 v8::Handle<v8::Object> global1 = context1->Global();
5586 global1->Set(v8_str("custom"), v8_num(1234));
5587 CHECK(!global0->Equals(global1));
5588 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
5589 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
5591 // Now create a new context with the old global
5592 LocalContext context2(0, templ, global1);
5593 context2->SetSecurityToken(password);
5594 v8::Handle<v8::Object> global2 = context2->Global();
5595 CHECK(global1->Equals(global2));
5596 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
5597 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
5601 THREADED_TEST(FunctionPrototypeAcrossContexts) {
5602 // Make sure that functions created by cloning boilerplates cannot
5603 // communicate through their __proto__ field.
5605 v8::HandleScope scope(CcTest::isolate());
5608 v8::Handle<v8::Object> global0 = env0->Global();
5609 v8::Handle<v8::Object> object0 =
5610 global0->Get(v8_str("Object")).As<v8::Object>();
5611 v8::Handle<v8::Object> tostring0 =
5612 object0->Get(v8_str("toString")).As<v8::Object>();
5613 v8::Handle<v8::Object> proto0 =
5614 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
5615 proto0->Set(v8_str("custom"), v8_num(1234));
5618 v8::Handle<v8::Object> global1 = env1->Global();
5619 v8::Handle<v8::Object> object1 =
5620 global1->Get(v8_str("Object")).As<v8::Object>();
5621 v8::Handle<v8::Object> tostring1 =
5622 object1->Get(v8_str("toString")).As<v8::Object>();
5623 v8::Handle<v8::Object> proto1 =
5624 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
5625 CHECK(!proto1->Has(v8_str("custom")));
5629 THREADED_TEST(Regress892105) {
5630 // Make sure that object and array literals created by cloning
5631 // boilerplates cannot communicate through their __proto__
5632 // field. This is rather difficult to check, but we try to add stuff
5633 // to Object.prototype and Array.prototype and create a new
5634 // environment. This should succeed.
5636 v8::HandleScope scope(CcTest::isolate());
5638 Local<String> source = v8_str(
5639 "Object.prototype.obj = 1234;"
5640 "Array.prototype.arr = 4567;"
5644 Local<Script> script0 = v8_compile(source);
5645 CHECK_EQ(8901.0, script0->Run()->NumberValue());
5648 Local<Script> script1 = v8_compile(source);
5649 CHECK_EQ(8901.0, script1->Run()->NumberValue());
5653 THREADED_TEST(UndetectableObject) {
5655 v8::HandleScope scope(env->GetIsolate());
5657 Local<v8::FunctionTemplate> desc =
5658 v8::FunctionTemplate::New(env->GetIsolate());
5659 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5661 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5662 env->Global()->Set(v8_str("undetectable"), obj);
5664 ExpectString("undetectable.toString()", "[object Object]");
5665 ExpectString("typeof undetectable", "undefined");
5666 ExpectString("typeof(undetectable)", "undefined");
5667 ExpectBoolean("typeof undetectable == 'undefined'", true);
5668 ExpectBoolean("typeof undetectable == 'object'", false);
5669 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
5670 ExpectBoolean("!undetectable", true);
5672 ExpectObject("true&&undetectable", obj);
5673 ExpectBoolean("false&&undetectable", false);
5674 ExpectBoolean("true||undetectable", true);
5675 ExpectObject("false||undetectable", obj);
5677 ExpectObject("undetectable&&true", obj);
5678 ExpectObject("undetectable&&false", obj);
5679 ExpectBoolean("undetectable||true", true);
5680 ExpectBoolean("undetectable||false", false);
5682 ExpectBoolean("undetectable==null", true);
5683 ExpectBoolean("null==undetectable", true);
5684 ExpectBoolean("undetectable==undefined", true);
5685 ExpectBoolean("undefined==undetectable", true);
5686 ExpectBoolean("undetectable==undetectable", true);
5689 ExpectBoolean("undetectable===null", false);
5690 ExpectBoolean("null===undetectable", false);
5691 ExpectBoolean("undetectable===undefined", false);
5692 ExpectBoolean("undefined===undetectable", false);
5693 ExpectBoolean("undetectable===undetectable", true);
5697 THREADED_TEST(VoidLiteral) {
5699 v8::Isolate* isolate = env->GetIsolate();
5700 v8::HandleScope scope(isolate);
5702 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
5703 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5705 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5706 env->Global()->Set(v8_str("undetectable"), obj);
5708 ExpectBoolean("undefined == void 0", true);
5709 ExpectBoolean("undetectable == void 0", true);
5710 ExpectBoolean("null == void 0", true);
5711 ExpectBoolean("undefined === void 0", true);
5712 ExpectBoolean("undetectable === void 0", false);
5713 ExpectBoolean("null === void 0", false);
5715 ExpectBoolean("void 0 == undefined", true);
5716 ExpectBoolean("void 0 == undetectable", true);
5717 ExpectBoolean("void 0 == null", true);
5718 ExpectBoolean("void 0 === undefined", true);
5719 ExpectBoolean("void 0 === undetectable", false);
5720 ExpectBoolean("void 0 === null", false);
5725 " return x === void 0;"
5727 " return e.toString();"
5730 "ReferenceError: x is not defined");
5734 " return void 0 === x;"
5736 " return e.toString();"
5739 "ReferenceError: x is not defined");
5743 THREADED_TEST(ExtensibleOnUndetectable) {
5745 v8::Isolate* isolate = env->GetIsolate();
5746 v8::HandleScope scope(isolate);
5748 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
5749 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
5751 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
5752 env->Global()->Set(v8_str("undetectable"), obj);
5754 Local<String> source = v8_str(
5755 "undetectable.x = 42;"
5758 Local<Script> script = v8_compile(source);
5760 CHECK(v8::Integer::New(isolate, 42)->Equals(script->Run()));
5762 ExpectBoolean("Object.isExtensible(undetectable)", true);
5764 source = v8_str("Object.preventExtensions(undetectable);");
5765 script = v8_compile(source);
5767 ExpectBoolean("Object.isExtensible(undetectable)", false);
5769 source = v8_str("undetectable.y = 2000;");
5770 script = v8_compile(source);
5772 ExpectBoolean("undetectable.y == undefined", true);
5776 // The point of this test is type checking. We run it only so compilers
5777 // don't complain about an unused function.
5778 TEST(PersistentHandles) {
5780 v8::Isolate* isolate = CcTest::isolate();
5781 v8::HandleScope scope(isolate);
5782 Local<String> str = v8_str("foo");
5783 v8::Persistent<String> p_str(isolate, str);
5785 Local<Script> scr = v8_compile("");
5786 v8::Persistent<Script> p_scr(isolate, scr);
5788 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5789 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
5794 static void HandleLogDelegator(
5795 const v8::FunctionCallbackInfo<v8::Value>& args) {
5796 ApiTestFuzzer::Fuzz();
5800 THREADED_TEST(GlobalObjectTemplate) {
5801 v8::Isolate* isolate = CcTest::isolate();
5802 v8::HandleScope handle_scope(isolate);
5803 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
5804 global_template->Set(v8_str("JSNI_Log"),
5805 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
5806 v8::Local<Context> context = Context::New(isolate, 0, global_template);
5807 Context::Scope context_scope(context);
5808 CompileRun("JSNI_Log('LOG')");
5812 static const char* kSimpleExtensionSource =
5818 TEST(SimpleExtensions) {
5819 v8::HandleScope handle_scope(CcTest::isolate());
5820 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
5821 const char* extension_names[] = {"simpletest"};
5822 v8::ExtensionConfiguration extensions(1, extension_names);
5823 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
5824 Context::Scope lock(context);
5825 v8::Handle<Value> result = CompileRun("Foo()");
5826 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
5830 static const char* kStackTraceFromExtensionSource =
5832 " throw new Error();"
5839 TEST(StackTraceInExtension) {
5840 v8::HandleScope handle_scope(CcTest::isolate());
5841 v8::RegisterExtension(
5842 new Extension("stacktracetest", kStackTraceFromExtensionSource));
5843 const char* extension_names[] = {"stacktracetest"};
5844 v8::ExtensionConfiguration extensions(1, extension_names);
5845 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
5846 Context::Scope lock(context);
5848 "function user() { bar(); }"
5850 "try{ user(); } catch (e) { error = e; }");
5851 CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
5852 CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
5853 CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
5857 TEST(NullExtensions) {
5858 v8::HandleScope handle_scope(CcTest::isolate());
5859 v8::RegisterExtension(new Extension("nulltest", NULL));
5860 const char* extension_names[] = {"nulltest"};
5861 v8::ExtensionConfiguration extensions(1, extension_names);
5862 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
5863 Context::Scope lock(context);
5864 v8::Handle<Value> result = CompileRun("1+3");
5865 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
5869 static const char* kEmbeddedExtensionSource =
5870 "function Ret54321(){return 54321;}~~@@$"
5871 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
5872 static const int kEmbeddedExtensionSourceValidLen = 34;
5875 TEST(ExtensionMissingSourceLength) {
5876 v8::HandleScope handle_scope(CcTest::isolate());
5877 v8::RegisterExtension(
5878 new Extension("srclentest_fail", kEmbeddedExtensionSource));
5879 const char* extension_names[] = {"srclentest_fail"};
5880 v8::ExtensionConfiguration extensions(1, extension_names);
5881 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
5882 CHECK(0 == *context);
5886 TEST(ExtensionWithSourceLength) {
5887 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
5888 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
5889 v8::HandleScope handle_scope(CcTest::isolate());
5890 i::ScopedVector<char> extension_name(32);
5891 i::SNPrintF(extension_name, "ext #%d", source_len);
5892 v8::RegisterExtension(new Extension(
5893 extension_name.start(), kEmbeddedExtensionSource, 0, 0, source_len));
5894 const char* extension_names[1] = {extension_name.start()};
5895 v8::ExtensionConfiguration extensions(1, extension_names);
5896 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
5897 if (source_len == kEmbeddedExtensionSourceValidLen) {
5898 Context::Scope lock(context);
5899 v8::Handle<Value> result = CompileRun("Ret54321()");
5900 CHECK(v8::Integer::New(CcTest::isolate(), 54321)->Equals(result));
5902 // Anything but exactly the right length should fail to compile.
5903 CHECK(0 == *context);
5909 static const char* kEvalExtensionSource1 =
5910 "function UseEval1() {"
5912 " return eval('x');"
5916 static const char* kEvalExtensionSource2 =
5920 " return eval('x');"
5922 " this.UseEval2 = e;"
5926 TEST(UseEvalFromExtension) {
5927 v8::HandleScope handle_scope(CcTest::isolate());
5928 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
5929 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
5930 const char* extension_names[] = {"evaltest1", "evaltest2"};
5931 v8::ExtensionConfiguration extensions(2, extension_names);
5932 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
5933 Context::Scope lock(context);
5934 v8::Handle<Value> result = CompileRun("UseEval1()");
5935 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
5936 result = CompileRun("UseEval2()");
5937 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
5941 static const char* kWithExtensionSource1 =
5942 "function UseWith1() {"
5944 " with({x:87}) { return x; }"
5948 static const char* kWithExtensionSource2 =
5952 " with ({x:87}) { return x; }"
5954 " this.UseWith2 = e;"
5958 TEST(UseWithFromExtension) {
5959 v8::HandleScope handle_scope(CcTest::isolate());
5960 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
5961 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
5962 const char* extension_names[] = {"withtest1", "withtest2"};
5963 v8::ExtensionConfiguration extensions(2, extension_names);
5964 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
5965 Context::Scope lock(context);
5966 v8::Handle<Value> result = CompileRun("UseWith1()");
5967 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 87)));
5968 result = CompileRun("UseWith2()");
5969 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 87)));
5973 TEST(AutoExtensions) {
5974 v8::HandleScope handle_scope(CcTest::isolate());
5975 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
5976 extension->set_auto_enable(true);
5977 v8::RegisterExtension(extension);
5978 v8::Handle<Context> context = Context::New(CcTest::isolate());
5979 Context::Scope lock(context);
5980 v8::Handle<Value> result = CompileRun("Foo()");
5981 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 4)));
5985 static const char* kSyntaxErrorInExtensionSource = "[";
5988 // Test that a syntax error in an extension does not cause a fatal
5989 // error but results in an empty context.
5990 TEST(SyntaxErrorExtensions) {
5991 v8::HandleScope handle_scope(CcTest::isolate());
5992 v8::RegisterExtension(
5993 new Extension("syntaxerror", kSyntaxErrorInExtensionSource));
5994 const char* extension_names[] = {"syntaxerror"};
5995 v8::ExtensionConfiguration extensions(1, extension_names);
5996 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
5997 CHECK(context.IsEmpty());
6001 static const char* kExceptionInExtensionSource = "throw 42";
6004 // Test that an exception when installing an extension does not cause
6005 // a fatal error but results in an empty context.
6006 TEST(ExceptionExtensions) {
6007 v8::HandleScope handle_scope(CcTest::isolate());
6008 v8::RegisterExtension(
6009 new Extension("exception", kExceptionInExtensionSource));
6010 const char* extension_names[] = {"exception"};
6011 v8::ExtensionConfiguration extensions(1, extension_names);
6012 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6013 CHECK(context.IsEmpty());
6017 static const char* kNativeCallInExtensionSource =
6018 "function call_runtime_last_index_of(x) {"
6019 " return %StringLastIndexOf(x, 'bob', 10);"
6023 static const char* kNativeCallTest =
6024 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
6026 // Test that a native runtime calls are supported in extensions.
6027 TEST(NativeCallInExtensions) {
6028 v8::HandleScope handle_scope(CcTest::isolate());
6029 v8::RegisterExtension(
6030 new Extension("nativecall", kNativeCallInExtensionSource));
6031 const char* extension_names[] = {"nativecall"};
6032 v8::ExtensionConfiguration extensions(1, extension_names);
6033 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6034 Context::Scope lock(context);
6035 v8::Handle<Value> result = CompileRun(kNativeCallTest);
6036 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 3)));
6040 class NativeFunctionExtension : public Extension {
6042 NativeFunctionExtension(const char* name, const char* source,
6043 v8::FunctionCallback fun = &Echo)
6044 : Extension(name, source), function_(fun) {}
6046 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6047 v8::Isolate* isolate, v8::Handle<v8::String> name) {
6048 return v8::FunctionTemplate::New(isolate, function_);
6051 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
6052 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
6056 v8::FunctionCallback function_;
6060 TEST(NativeFunctionDeclaration) {
6061 v8::HandleScope handle_scope(CcTest::isolate());
6062 const char* name = "nativedecl";
6063 v8::RegisterExtension(
6064 new NativeFunctionExtension(name, "native function foo();"));
6065 const char* extension_names[] = {name};
6066 v8::ExtensionConfiguration extensions(1, extension_names);
6067 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6068 Context::Scope lock(context);
6069 v8::Handle<Value> result = CompileRun("foo(42);");
6070 CHECK(result->Equals(v8::Integer::New(CcTest::isolate(), 42)));
6074 TEST(NativeFunctionDeclarationError) {
6075 v8::HandleScope handle_scope(CcTest::isolate());
6076 const char* name = "nativedeclerr";
6077 // Syntax error in extension code.
6078 v8::RegisterExtension(
6079 new NativeFunctionExtension(name, "native\nfunction foo();"));
6080 const char* extension_names[] = {name};
6081 v8::ExtensionConfiguration extensions(1, extension_names);
6082 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6083 CHECK(context.IsEmpty());
6087 TEST(NativeFunctionDeclarationErrorEscape) {
6088 v8::HandleScope handle_scope(CcTest::isolate());
6089 const char* name = "nativedeclerresc";
6090 // Syntax error in extension code - escape code in "native" means that
6091 // it's not treated as a keyword.
6092 v8::RegisterExtension(
6093 new NativeFunctionExtension(name, "nativ\\u0065 function foo();"));
6094 const char* extension_names[] = {name};
6095 v8::ExtensionConfiguration extensions(1, extension_names);
6096 v8::Handle<Context> context = Context::New(CcTest::isolate(), &extensions);
6097 CHECK(context.IsEmpty());
6101 static void CheckDependencies(const char* name, const char* expected) {
6102 v8::HandleScope handle_scope(CcTest::isolate());
6103 v8::ExtensionConfiguration config(1, &name);
6104 LocalContext context(&config);
6105 CHECK(String::NewFromUtf8(CcTest::isolate(), expected)
6106 ->Equals(context->Global()->Get(v8_str("loaded"))));
6117 THREADED_TEST(ExtensionDependency) {
6118 static const char* kEDeps[] = {"D"};
6119 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
6120 static const char* kDDeps[] = {"B", "C"};
6121 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
6122 static const char* kBCDeps[] = {"A"};
6123 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
6124 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
6125 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
6126 CheckDependencies("A", "undefinedA");
6127 CheckDependencies("B", "undefinedAB");
6128 CheckDependencies("C", "undefinedAC");
6129 CheckDependencies("D", "undefinedABCD");
6130 CheckDependencies("E", "undefinedABCDE");
6131 v8::HandleScope handle_scope(CcTest::isolate());
6132 static const char* exts[2] = {"C", "E"};
6133 v8::ExtensionConfiguration config(2, exts);
6134 LocalContext context(&config);
6135 CHECK(v8_str("undefinedACBDE")
6136 ->Equals(context->Global()->Get(v8_str("loaded"))));
6140 static const char* kExtensionTestScript =
6141 "native function A();"
6142 "native function B();"
6143 "native function C();"
6145 " if (i == 0) return A();"
6146 " if (i == 1) return B();"
6147 " if (i == 2) return C();"
6151 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
6152 ApiTestFuzzer::Fuzz();
6153 if (args.IsConstructCall()) {
6154 args.This()->Set(v8_str("data"), args.Data());
6155 args.GetReturnValue().SetNull();
6158 args.GetReturnValue().Set(args.Data());
6162 class FunctionExtension : public Extension {
6164 FunctionExtension() : Extension("functiontest", kExtensionTestScript) {}
6165 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
6166 v8::Isolate* isolate, v8::Handle<String> name);
6170 static int lookup_count = 0;
6171 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
6172 v8::Isolate* isolate, v8::Handle<String> name) {
6174 if (name->Equals(v8_str("A"))) {
6175 return v8::FunctionTemplate::New(isolate, CallFun,
6176 v8::Integer::New(isolate, 8));
6177 } else if (name->Equals(v8_str("B"))) {
6178 return v8::FunctionTemplate::New(isolate, CallFun,
6179 v8::Integer::New(isolate, 7));
6180 } else if (name->Equals(v8_str("C"))) {
6181 return v8::FunctionTemplate::New(isolate, CallFun,
6182 v8::Integer::New(isolate, 6));
6184 return v8::Handle<v8::FunctionTemplate>();
6189 THREADED_TEST(FunctionLookup) {
6190 v8::RegisterExtension(new FunctionExtension());
6191 v8::HandleScope handle_scope(CcTest::isolate());
6192 static const char* exts[1] = {"functiontest"};
6193 v8::ExtensionConfiguration config(1, exts);
6194 LocalContext context(&config);
6195 CHECK_EQ(3, lookup_count);
6196 CHECK(v8::Integer::New(CcTest::isolate(), 8)->Equals(CompileRun("Foo(0)")));
6197 CHECK(v8::Integer::New(CcTest::isolate(), 7)->Equals(CompileRun("Foo(1)")));
6198 CHECK(v8::Integer::New(CcTest::isolate(), 6)->Equals(CompileRun("Foo(2)")));
6202 THREADED_TEST(NativeFunctionConstructCall) {
6203 v8::RegisterExtension(new FunctionExtension());
6204 v8::HandleScope handle_scope(CcTest::isolate());
6205 static const char* exts[1] = {"functiontest"};
6206 v8::ExtensionConfiguration config(1, exts);
6207 LocalContext context(&config);
6208 for (int i = 0; i < 10; i++) {
6209 // Run a few times to ensure that allocation of objects doesn't
6210 // change behavior of a constructor function.
6211 CHECK(v8::Integer::New(CcTest::isolate(), 8)
6212 ->Equals(CompileRun("(new A()).data")));
6213 CHECK(v8::Integer::New(CcTest::isolate(), 7)
6214 ->Equals(CompileRun("(new B()).data")));
6215 CHECK(v8::Integer::New(CcTest::isolate(), 6)
6216 ->Equals(CompileRun("(new C()).data")));
6221 static const char* last_location;
6222 static const char* last_message;
6223 void StoringErrorCallback(const char* location, const char* message) {
6224 if (last_location == NULL) {
6225 last_location = location;
6226 last_message = message;
6231 // ErrorReporting creates a circular extensions configuration and
6232 // tests that the fatal error handler gets called. This renders V8
6233 // unusable and therefore this test cannot be run in parallel.
6234 TEST(ErrorReporting) {
6235 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
6236 static const char* aDeps[] = {"B"};
6237 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
6238 static const char* bDeps[] = {"A"};
6239 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
6240 last_location = NULL;
6241 v8::ExtensionConfiguration config(1, bDeps);
6242 v8::Handle<Context> context = Context::New(CcTest::isolate(), &config);
6243 CHECK(context.IsEmpty());
6244 CHECK(last_location);
6248 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
6249 v8::Handle<Value> data) {
6250 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
6251 CHECK(v8::Undefined(CcTest::isolate())
6252 ->Equals(message->GetScriptOrigin().ResourceName()));
6253 message->GetLineNumber();
6254 message->GetSourceLine();
6258 THREADED_TEST(ErrorWithMissingScriptInfo) {
6259 LocalContext context;
6260 v8::HandleScope scope(context->GetIsolate());
6261 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
6262 CompileRun("throw Error()");
6263 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
6267 struct FlagAndPersistent {
6269 v8::Persistent<v8::Object> handle;
6273 static void SetFlag(const v8::PhantomCallbackData<FlagAndPersistent>& data) {
6274 data.GetParameter()->flag = true;
6278 static void IndependentWeakHandle(bool global_gc, bool interlinked) {
6279 v8::Isolate* iso = CcTest::isolate();
6280 v8::HandleScope scope(iso);
6281 v8::Handle<Context> context = Context::New(iso);
6282 Context::Scope context_scope(context);
6284 FlagAndPersistent object_a, object_b;
6286 intptr_t big_heap_size;
6289 v8::HandleScope handle_scope(iso);
6290 Local<Object> a(v8::Object::New(iso));
6291 Local<Object> b(v8::Object::New(iso));
6292 object_a.handle.Reset(iso, a);
6293 object_b.handle.Reset(iso, b);
6295 a->Set(v8_str("x"), b);
6296 b->Set(v8_str("x"), a);
6299 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
6301 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6303 // We are relying on this creating a big flag array and reserving the space
6305 v8::Handle<Value> big_array = CompileRun("new Array(50000)");
6306 a->Set(v8_str("y"), big_array);
6307 big_heap_size = CcTest::heap()->SizeOfObjects();
6310 object_a.flag = false;
6311 object_b.flag = false;
6312 object_a.handle.SetPhantom(&object_a, &SetFlag);
6313 object_b.handle.SetPhantom(&object_b, &SetFlag);
6314 CHECK(!object_b.handle.IsIndependent());
6315 object_a.handle.MarkIndependent();
6316 object_b.handle.MarkIndependent();
6317 CHECK(object_b.handle.IsIndependent());
6319 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
6321 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6323 // A single GC should be enough to reclaim the memory, since we are using
6325 CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
6326 CHECK(object_a.flag);
6327 CHECK(object_b.flag);
6331 THREADED_TEST(IndependentWeakHandle) {
6332 IndependentWeakHandle(false, false);
6333 IndependentWeakHandle(false, true);
6334 IndependentWeakHandle(true, false);
6335 IndependentWeakHandle(true, true);
6341 explicit Trivial(int x) : x_(x) {}
6343 int x() { return x_; }
6344 void set_x(int x) { x_ = x; }
6353 Trivial2(int x, int y) : y_(y), x_(x) {}
6355 int x() { return x_; }
6356 void set_x(int x) { x_ = x; }
6358 int y() { return y_; }
6359 void set_y(int y) { y_ = y; }
6367 void CheckInternalFields(
6368 const v8::PhantomCallbackData<v8::Persistent<v8::Object>>& data) {
6369 v8::Persistent<v8::Object>* handle = data.GetParameter();
6371 Trivial* t1 = reinterpret_cast<Trivial*>(data.GetInternalField1());
6372 Trivial2* t2 = reinterpret_cast<Trivial2*>(data.GetInternalField2());
6373 CHECK_EQ(42, t1->x());
6374 CHECK_EQ(103, t2->x());
6376 t2->set_x(33550336);
6380 void InternalFieldCallback(bool global_gc) {
6382 v8::Isolate* isolate = env->GetIsolate();
6383 v8::HandleScope scope(isolate);
6385 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
6386 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
6389 instance_templ->SetInternalFieldCount(2);
6391 v8::HandleScope scope(isolate);
6392 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
6393 v8::Persistent<v8::Object> handle(isolate, obj);
6394 CHECK_EQ(2, obj->InternalFieldCount());
6395 CHECK(obj->GetInternalField(0)->IsUndefined());
6396 t1 = new Trivial(42);
6397 t2 = new Trivial2(103, 9);
6399 obj->SetAlignedPointerInInternalField(0, t1);
6400 t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
6401 CHECK_EQ(42, t1->x());
6403 obj->SetAlignedPointerInInternalField(1, t2);
6405 reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
6406 CHECK_EQ(103, t2->x());
6408 handle.SetPhantom<v8::Persistent<v8::Object>>(&handle, CheckInternalFields,
6411 handle.MarkIndependent();
6415 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
6417 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6420 CHECK_EQ(1729, t1->x());
6421 CHECK_EQ(33550336, t2->x());
6428 THREADED_TEST(InternalFieldCallback) {
6429 InternalFieldCallback(false);
6430 InternalFieldCallback(true);
6434 static void ResetUseValueAndSetFlag(
6435 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6436 // Blink will reset the handle, and then use the other handle, so they
6437 // can't use the same backing slot.
6438 data.GetParameter()->handle.Reset();
6439 data.GetValue()->IsBoolean(); // Make sure the handle still works.
6440 data.GetParameter()->flag = true;
6444 static void ResetWeakHandle(bool global_gc) {
6445 v8::Isolate* iso = CcTest::isolate();
6446 v8::HandleScope scope(iso);
6447 v8::Handle<Context> context = Context::New(iso);
6448 Context::Scope context_scope(context);
6450 FlagAndPersistent object_a, object_b;
6453 v8::HandleScope handle_scope(iso);
6454 Local<Object> a(v8::Object::New(iso));
6455 Local<Object> b(v8::Object::New(iso));
6456 object_a.handle.Reset(iso, a);
6457 object_b.handle.Reset(iso, b);
6459 CcTest::heap()->CollectAllGarbage(
6460 TestHeap::Heap::kAbortIncrementalMarkingMask);
6462 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6466 object_a.flag = false;
6467 object_b.flag = false;
6468 object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
6469 object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
6471 object_a.handle.MarkIndependent();
6472 object_b.handle.MarkIndependent();
6473 CHECK(object_b.handle.IsIndependent());
6476 CcTest::heap()->CollectAllGarbage(
6477 TestHeap::Heap::kAbortIncrementalMarkingMask);
6479 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6481 CHECK(object_a.flag);
6482 CHECK(object_b.flag);
6486 THREADED_TEST(ResetWeakHandle) {
6487 ResetWeakHandle(false);
6488 ResetWeakHandle(true);
6492 static void InvokeScavenge() { CcTest::heap()->CollectGarbage(i::NEW_SPACE); }
6495 static void InvokeMarkSweep() {
6496 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
6500 static void ForceScavenge(
6501 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6502 data.GetParameter()->handle.Reset();
6503 data.GetParameter()->flag = true;
6508 static void ForceMarkSweep(
6509 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6510 data.GetParameter()->handle.Reset();
6511 data.GetParameter()->flag = true;
6516 THREADED_TEST(GCFromWeakCallbacks) {
6517 v8::Isolate* isolate = CcTest::isolate();
6518 v8::HandleScope scope(isolate);
6519 v8::Handle<Context> context = Context::New(isolate);
6520 Context::Scope context_scope(context);
6522 static const int kNumberOfGCTypes = 2;
6523 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
6525 Callback gc_forcing_callback[kNumberOfGCTypes] =
6526 {&ForceScavenge, &ForceMarkSweep};
6528 typedef void (*GCInvoker)();
6529 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
6531 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
6532 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
6533 FlagAndPersistent object;
6535 v8::HandleScope handle_scope(isolate);
6536 object.handle.Reset(isolate, v8::Object::New(isolate));
6538 object.flag = false;
6539 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
6540 object.handle.MarkIndependent();
6541 invoke_gc[outer_gc]();
6548 static void RevivingCallback(
6549 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
6550 data.GetParameter()->handle.ClearWeak();
6551 data.GetParameter()->flag = true;
6555 THREADED_TEST(IndependentHandleRevival) {
6556 v8::Isolate* isolate = CcTest::isolate();
6557 v8::HandleScope scope(isolate);
6558 v8::Handle<Context> context = Context::New(isolate);
6559 Context::Scope context_scope(context);
6561 FlagAndPersistent object;
6563 v8::HandleScope handle_scope(isolate);
6564 v8::Local<v8::Object> o = v8::Object::New(isolate);
6565 object.handle.Reset(isolate, o);
6566 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
6567 v8::Local<String> y_str = v8_str("y");
6568 o->Set(y_str, y_str);
6570 object.flag = false;
6571 object.handle.SetWeak(&object, &RevivingCallback);
6572 object.handle.MarkIndependent();
6573 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
6575 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
6577 v8::HandleScope handle_scope(isolate);
6578 v8::Local<v8::Object> o =
6579 v8::Local<v8::Object>::New(isolate, object.handle);
6580 v8::Local<String> y_str = v8_str("y");
6581 CHECK(v8::Integer::New(isolate, 1)->Equals(o->Get(v8_str("x"))));
6582 CHECK(o->Get(y_str)->Equals(y_str));
6587 v8::Handle<Function> args_fun;
6590 static void ArgumentsTestCallback(
6591 const v8::FunctionCallbackInfo<v8::Value>& args) {
6592 ApiTestFuzzer::Fuzz();
6593 v8::Isolate* isolate = args.GetIsolate();
6594 CHECK(args_fun->Equals(args.Callee()));
6595 CHECK_EQ(3, args.Length());
6596 CHECK(v8::Integer::New(isolate, 1)->Equals(args[0]));
6597 CHECK(v8::Integer::New(isolate, 2)->Equals(args[1]));
6598 CHECK(v8::Integer::New(isolate, 3)->Equals(args[2]));
6599 CHECK(v8::Undefined(isolate)->Equals(args[3]));
6600 v8::HandleScope scope(args.GetIsolate());
6601 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
6605 THREADED_TEST(Arguments) {
6606 v8::Isolate* isolate = CcTest::isolate();
6607 v8::HandleScope scope(isolate);
6608 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
6609 global->Set(v8_str("f"),
6610 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
6611 LocalContext context(NULL, global);
6612 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
6613 v8_compile("f(1, 2, 3)")->Run();
6617 static int p_getter_count;
6618 static int p_getter_count2;
6621 static void PGetter(Local<String> name,
6622 const v8::PropertyCallbackInfo<v8::Value>& info) {
6623 ApiTestFuzzer::Fuzz();
6625 v8::Handle<v8::Object> global =
6626 info.GetIsolate()->GetCurrentContext()->Global();
6627 CHECK(info.Holder()->Equals(global->Get(v8_str("o1"))));
6628 if (name->Equals(v8_str("p1"))) {
6629 CHECK(info.This()->Equals(global->Get(v8_str("o1"))));
6630 } else if (name->Equals(v8_str("p2"))) {
6631 CHECK(info.This()->Equals(global->Get(v8_str("o2"))));
6632 } else if (name->Equals(v8_str("p3"))) {
6633 CHECK(info.This()->Equals(global->Get(v8_str("o3"))));
6634 } else if (name->Equals(v8_str("p4"))) {
6635 CHECK(info.This()->Equals(global->Get(v8_str("o4"))));
6640 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
6641 ApiTestFuzzer::Fuzz();
6642 LocalContext context;
6643 context->Global()->Set(v8_str("o1"), obj->NewInstance());
6645 "o1.__proto__ = { };"
6646 "var o2 = { __proto__: o1 };"
6647 "var o3 = { __proto__: o2 };"
6648 "var o4 = { __proto__: o3 };"
6649 "for (var i = 0; i < 10; i++) o4.p4;"
6650 "for (var i = 0; i < 10; i++) o3.p3;"
6651 "for (var i = 0; i < 10; i++) o2.p2;"
6652 "for (var i = 0; i < 10; i++) o1.p1;");
6656 static void PGetter2(Local<Name> name,
6657 const v8::PropertyCallbackInfo<v8::Value>& info) {
6658 ApiTestFuzzer::Fuzz();
6660 v8::Handle<v8::Object> global =
6661 info.GetIsolate()->GetCurrentContext()->Global();
6662 CHECK(info.Holder()->Equals(global->Get(v8_str("o1"))));
6663 if (name->Equals(v8_str("p1"))) {
6664 CHECK(info.This()->Equals(global->Get(v8_str("o1"))));
6665 } else if (name->Equals(v8_str("p2"))) {
6666 CHECK(info.This()->Equals(global->Get(v8_str("o2"))));
6667 } else if (name->Equals(v8_str("p3"))) {
6668 CHECK(info.This()->Equals(global->Get(v8_str("o3"))));
6669 } else if (name->Equals(v8_str("p4"))) {
6670 CHECK(info.This()->Equals(global->Get(v8_str("o4"))));
6675 THREADED_TEST(GetterHolders) {
6676 v8::Isolate* isolate = CcTest::isolate();
6677 v8::HandleScope scope(isolate);
6678 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
6679 obj->SetAccessor(v8_str("p1"), PGetter);
6680 obj->SetAccessor(v8_str("p2"), PGetter);
6681 obj->SetAccessor(v8_str("p3"), PGetter);
6682 obj->SetAccessor(v8_str("p4"), PGetter);
6685 CHECK_EQ(40, p_getter_count);
6689 THREADED_TEST(PreInterceptorHolders) {
6690 v8::Isolate* isolate = CcTest::isolate();
6691 v8::HandleScope scope(isolate);
6692 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
6693 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
6694 p_getter_count2 = 0;
6696 CHECK_EQ(40, p_getter_count2);
6700 THREADED_TEST(ObjectInstantiation) {
6701 v8::Isolate* isolate = CcTest::isolate();
6702 v8::HandleScope scope(isolate);
6703 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
6704 templ->SetAccessor(v8_str("t"), PGetter2);
6705 LocalContext context;
6706 context->Global()->Set(v8_str("o"), templ->NewInstance());
6707 for (int i = 0; i < 100; i++) {
6708 v8::HandleScope inner_scope(CcTest::isolate());
6709 v8::Handle<v8::Object> obj = templ->NewInstance();
6710 CHECK(!obj->Equals(context->Global()->Get(v8_str("o"))));
6711 context->Global()->Set(v8_str("o2"), obj);
6712 v8::Handle<Value> value =
6713 CompileRun("o.__proto__ === o2.__proto__");
6714 CHECK(v8::True(isolate)->Equals(value));
6715 context->Global()->Set(v8_str("o"), obj);
6720 static int StrCmp16(uint16_t* a, uint16_t* b) {
6722 if (*a == 0 && *b == 0) return 0;
6723 if (*a != *b) return 0 + *a - *b;
6730 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
6732 if (n-- == 0) return 0;
6733 if (*a == 0 && *b == 0) return 0;
6734 if (*a != *b) return 0 + *a - *b;
6741 int GetUtf8Length(Handle<String> str) {
6742 int len = str->Utf8Length();
6744 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
6745 i::String::Flatten(istr);
6746 len = str->Utf8Length();
6752 THREADED_TEST(StringWrite) {
6753 LocalContext context;
6754 v8::HandleScope scope(context->GetIsolate());
6755 v8::Handle<String> str = v8_str("abcde");
6756 // abc<Icelandic eth><Unicode snowman>.
6757 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
6758 v8::Handle<String> str3 = v8::String::NewFromUtf8(
6759 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
6760 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
6761 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
6762 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
6763 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
6764 // single lead surrogate
6765 uint16_t lead[1] = { 0xd800 };
6766 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
6767 context->GetIsolate(), lead, v8::String::kNormalString, 1);
6768 // single trail surrogate
6769 uint16_t trail[1] = { 0xdc00 };
6770 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
6771 context->GetIsolate(), trail, v8::String::kNormalString, 1);
6773 uint16_t pair[2] = { 0xd800, 0xdc00 };
6774 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
6775 context->GetIsolate(), pair, v8::String::kNormalString, 2);
6776 const int kStride = 4; // Must match stride in for loops in JS below.
6779 "for (var i = 0; i < 0xd800; i += 4) {"
6780 " left = left + String.fromCharCode(i);"
6784 "for (var i = 0; i < 0xd800; i += 4) {"
6785 " right = String.fromCharCode(i) + right;"
6787 v8::Handle<v8::Object> global = context->Global();
6788 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
6789 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
6791 CHECK_EQ(5, str2->Length());
6792 CHECK_EQ(0xd800 / kStride, left_tree->Length());
6793 CHECK_EQ(0xd800 / kStride, right_tree->Length());
6796 char utf8buf[0xd800 * 3];
6801 memset(utf8buf, 0x1, 1000);
6802 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
6804 CHECK_EQ(5, charlen);
6805 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
6807 memset(utf8buf, 0x1, 1000);
6808 len = str2->WriteUtf8(utf8buf, 8, &charlen);
6810 CHECK_EQ(5, charlen);
6811 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
6813 memset(utf8buf, 0x1, 1000);
6814 len = str2->WriteUtf8(utf8buf, 7, &charlen);
6816 CHECK_EQ(4, charlen);
6817 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
6819 memset(utf8buf, 0x1, 1000);
6820 len = str2->WriteUtf8(utf8buf, 6, &charlen);
6822 CHECK_EQ(4, charlen);
6823 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
6825 memset(utf8buf, 0x1, 1000);
6826 len = str2->WriteUtf8(utf8buf, 5, &charlen);
6828 CHECK_EQ(4, charlen);
6829 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
6831 memset(utf8buf, 0x1, 1000);
6832 len = str2->WriteUtf8(utf8buf, 4, &charlen);
6834 CHECK_EQ(3, charlen);
6835 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
6837 memset(utf8buf, 0x1, 1000);
6838 len = str2->WriteUtf8(utf8buf, 3, &charlen);
6840 CHECK_EQ(3, charlen);
6841 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
6843 memset(utf8buf, 0x1, 1000);
6844 len = str2->WriteUtf8(utf8buf, 2, &charlen);
6846 CHECK_EQ(2, charlen);
6847 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
6849 // allow orphan surrogates by default
6850 memset(utf8buf, 0x1, 1000);
6851 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
6853 CHECK_EQ(8, charlen);
6854 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
6856 // replace orphan surrogates with unicode replacement character
6857 memset(utf8buf, 0x1, 1000);
6858 len = orphans_str->WriteUtf8(utf8buf,
6861 String::REPLACE_INVALID_UTF8);
6863 CHECK_EQ(8, charlen);
6864 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
6866 // replace single lead surrogate with unicode replacement character
6867 memset(utf8buf, 0x1, 1000);
6868 len = lead_str->WriteUtf8(utf8buf,
6871 String::REPLACE_INVALID_UTF8);
6873 CHECK_EQ(1, charlen);
6874 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
6876 // replace single trail surrogate with unicode replacement character
6877 memset(utf8buf, 0x1, 1000);
6878 len = trail_str->WriteUtf8(utf8buf,
6881 String::REPLACE_INVALID_UTF8);
6883 CHECK_EQ(1, charlen);
6884 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
6886 // do not replace / write anything if surrogate pair does not fit the buffer
6888 memset(utf8buf, 0x1, 1000);
6889 len = pair_str->WriteUtf8(utf8buf,
6892 String::REPLACE_INVALID_UTF8);
6894 CHECK_EQ(0, charlen);
6896 memset(utf8buf, 0x1, sizeof(utf8buf));
6897 len = GetUtf8Length(left_tree);
6899 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
6900 CHECK_EQ(utf8_expected, len);
6901 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
6902 CHECK_EQ(utf8_expected, len);
6903 CHECK_EQ(0xd800 / kStride, charlen);
6904 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
6905 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
6906 CHECK_EQ(0xc0 - kStride,
6907 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
6908 CHECK_EQ(1, utf8buf[utf8_expected]);
6910 memset(utf8buf, 0x1, sizeof(utf8buf));
6911 len = GetUtf8Length(right_tree);
6912 CHECK_EQ(utf8_expected, len);
6913 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
6914 CHECK_EQ(utf8_expected, len);
6915 CHECK_EQ(0xd800 / kStride, charlen);
6916 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
6917 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
6918 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
6919 CHECK_EQ(1, utf8buf[utf8_expected]);
6921 memset(buf, 0x1, sizeof(buf));
6922 memset(wbuf, 0x1, sizeof(wbuf));
6923 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
6925 len = str->Write(wbuf);
6927 CHECK_EQ(0, strcmp("abcde", buf));
6928 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
6929 CHECK_EQ(0, StrCmp16(answer1, wbuf));
6931 memset(buf, 0x1, sizeof(buf));
6932 memset(wbuf, 0x1, sizeof(wbuf));
6933 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
6935 len = str->Write(wbuf, 0, 4);
6937 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
6938 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
6939 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
6941 memset(buf, 0x1, sizeof(buf));
6942 memset(wbuf, 0x1, sizeof(wbuf));
6943 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
6945 len = str->Write(wbuf, 0, 5);
6947 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
6948 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
6949 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
6951 memset(buf, 0x1, sizeof(buf));
6952 memset(wbuf, 0x1, sizeof(wbuf));
6953 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
6955 len = str->Write(wbuf, 0, 6);
6957 CHECK_EQ(0, strcmp("abcde", buf));
6958 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
6959 CHECK_EQ(0, StrCmp16(answer4, wbuf));
6961 memset(buf, 0x1, sizeof(buf));
6962 memset(wbuf, 0x1, sizeof(wbuf));
6963 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
6965 len = str->Write(wbuf, 4, -1);
6967 CHECK_EQ(0, strcmp("e", buf));
6968 uint16_t answer5[] = {'e', '\0'};
6969 CHECK_EQ(0, StrCmp16(answer5, wbuf));
6971 memset(buf, 0x1, sizeof(buf));
6972 memset(wbuf, 0x1, sizeof(wbuf));
6973 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
6975 len = str->Write(wbuf, 4, 6);
6977 CHECK_EQ(0, strcmp("e", buf));
6978 CHECK_EQ(0, StrCmp16(answer5, wbuf));
6980 memset(buf, 0x1, sizeof(buf));
6981 memset(wbuf, 0x1, sizeof(wbuf));
6982 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
6984 len = str->Write(wbuf, 4, 1);
6986 CHECK_EQ(0, strncmp("e\1", buf, 2));
6987 uint16_t answer6[] = {'e', 0x101};
6988 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
6990 memset(buf, 0x1, sizeof(buf));
6991 memset(wbuf, 0x1, sizeof(wbuf));
6992 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
6994 len = str->Write(wbuf, 3, 1);
6996 CHECK_EQ(0, strncmp("d\1", buf, 2));
6997 uint16_t answer7[] = {'d', 0x101};
6998 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
7000 memset(wbuf, 0x1, sizeof(wbuf));
7002 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
7004 CHECK_EQ('X', wbuf[5]);
7005 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
7006 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
7007 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
7008 CHECK_NE(0, StrCmp16(answer8b, wbuf));
7010 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
7012 memset(buf, 0x1, sizeof(buf));
7014 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
7017 String::NO_NULL_TERMINATION);
7019 CHECK_EQ('X', buf[5]);
7020 CHECK_EQ(0, strncmp("abcde", buf, 5));
7021 CHECK_NE(0, strcmp("abcde", buf));
7023 CHECK_EQ(0, strcmp("abcde", buf));
7025 memset(utf8buf, 0x1, sizeof(utf8buf));
7027 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7028 String::NO_NULL_TERMINATION);
7030 CHECK_EQ('X', utf8buf[8]);
7031 CHECK_EQ(5, charlen);
7032 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
7033 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7035 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
7037 memset(utf8buf, 0x1, sizeof(utf8buf));
7039 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
7040 String::NO_NULL_TERMINATION);
7042 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
7043 CHECK_EQ(5, charlen);
7045 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
7047 memset(buf, 0x1, sizeof(buf));
7048 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
7050 CHECK_EQ(0, strcmp("abc", buf));
7051 CHECK_EQ(0, buf[3]);
7052 CHECK_EQ(0, strcmp("def", buf + 4));
7054 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
7055 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
7056 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
7060 static void Utf16Helper(
7061 LocalContext& context, // NOLINT
7063 const char* lengths_name,
7065 Local<v8::Array> a =
7066 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7067 Local<v8::Array> alens =
7068 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7069 for (int i = 0; i < len; i++) {
7070 Local<v8::String> string =
7071 Local<v8::String>::Cast(a->Get(i));
7072 Local<v8::Number> expected_len =
7073 Local<v8::Number>::Cast(alens->Get(i));
7074 int length = GetUtf8Length(string);
7075 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
7080 static uint16_t StringGet(Handle<String> str, int index) {
7081 i::Handle<i::String> istring =
7082 v8::Utils::OpenHandle(String::Cast(*str));
7083 return istring->Get(index);
7087 static void WriteUtf8Helper(
7088 LocalContext& context, // NOLINT
7090 const char* lengths_name,
7092 Local<v8::Array> b =
7093 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
7094 Local<v8::Array> alens =
7095 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
7098 for (int i = 0; i < len; i++) {
7099 Local<v8::String> string =
7100 Local<v8::String>::Cast(b->Get(i));
7101 Local<v8::Number> expected_len =
7102 Local<v8::Number>::Cast(alens->Get(i));
7103 int utf8_length = static_cast<int>(expected_len->Value());
7104 for (int j = utf8_length + 1; j >= 0; j--) {
7105 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
7106 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
7109 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
7111 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
7112 CHECK_GE(utf8_length + 1, utf8_written);
7113 CHECK_GE(utf8_length, utf8_written2);
7114 for (int k = 0; k < utf8_written2; k++) {
7115 CHECK_EQ(buffer[k], buffer2[k]);
7117 CHECK(nchars * 3 >= utf8_written - 1);
7118 CHECK(nchars <= utf8_written);
7119 if (j == utf8_length + 1) {
7120 CHECK_EQ(utf8_written2, utf8_length);
7121 CHECK_EQ(utf8_written2 + 1, utf8_written);
7123 CHECK_EQ(buffer[utf8_written], 42);
7124 if (j > utf8_length) {
7125 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
7126 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
7127 Handle<String> roundtrip = v8_str(buffer);
7128 CHECK(roundtrip->Equals(string));
7130 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7132 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
7134 uint16_t trail = StringGet(string, nchars - 1);
7135 uint16_t lead = StringGet(string, nchars - 2);
7136 if (((lead & 0xfc00) == 0xd800) &&
7137 ((trail & 0xfc00) == 0xdc00)) {
7138 unsigned u1 = buffer2[utf8_written2 - 4];
7139 unsigned u2 = buffer2[utf8_written2 - 3];
7140 unsigned u3 = buffer2[utf8_written2 - 2];
7141 unsigned u4 = buffer2[utf8_written2 - 1];
7142 CHECK_EQ((u1 & 0xf8), 0xf0u);
7143 CHECK_EQ((u2 & 0xc0), 0x80u);
7144 CHECK_EQ((u3 & 0xc0), 0x80u);
7145 CHECK_EQ((u4 & 0xc0), 0x80u);
7146 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
7147 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
7148 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
7149 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
7150 CHECK_EQ((u1 & 0x3), c >> 18);
7158 THREADED_TEST(Utf16) {
7159 LocalContext context;
7160 v8::HandleScope scope(context->GetIsolate());
7162 "var pad = '01234567890123456789';"
7164 "var plens = [20, 3, 3];"
7165 "p.push('01234567890123456789');"
7166 "var lead = 0xd800;"
7167 "var trail = 0xdc00;"
7168 "p.push(String.fromCharCode(0xd800));"
7169 "p.push(String.fromCharCode(0xdc00));"
7174 "for (var i = 0; i < 3; i++) {"
7175 " p[1] = String.fromCharCode(lead++);"
7176 " for (var j = 0; j < 3; j++) {"
7177 " p[2] = String.fromCharCode(trail++);"
7178 " a.push(p[i] + p[j]);"
7179 " b.push(p[i] + p[j]);"
7180 " c.push(p[i] + p[j]);"
7181 " alens.push(plens[i] + plens[j]);"
7184 "alens[5] -= 2;" // Here the surrogate pairs match up.
7189 "for (var m = 0; m < 9; m++) {"
7190 " for (var n = 0; n < 9; n++) {"
7191 " a2.push(a[m] + a[n]);"
7192 " b2.push(b[m] + b[n]);"
7193 " var newc = 'x' + c[m] + c[n] + 'y';"
7194 " c2.push(newc.substring(1, newc.length - 1));"
7195 " var utf = alens[m] + alens[n];" // And here.
7196 // The 'n's that start with 0xdc.. are 6-8
7197 // The 'm's that end with 0xd8.. are 1, 4 and 7
7198 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
7199 " a2lens.push(utf);"
7202 Utf16Helper(context, "a", "alens", 9);
7203 Utf16Helper(context, "a2", "a2lens", 81);
7204 WriteUtf8Helper(context, "b", "alens", 9);
7205 WriteUtf8Helper(context, "b2", "a2lens", 81);
7206 WriteUtf8Helper(context, "c2", "a2lens", 81);
7210 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
7211 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
7212 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
7213 return *is1 == *is2;
7216 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
7218 Handle<String> symbol1 =
7219 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
7220 Handle<String> symbol2 =
7221 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
7222 CHECK(SameSymbol(symbol1, symbol2));
7226 THREADED_TEST(Utf16Symbol) {
7227 LocalContext context;
7228 v8::HandleScope scope(context->GetIsolate());
7230 Handle<String> symbol1 = v8::String::NewFromUtf8(
7231 context->GetIsolate(), "abc", v8::String::kInternalizedString);
7232 Handle<String> symbol2 = v8::String::NewFromUtf8(
7233 context->GetIsolate(), "abc", v8::String::kInternalizedString);
7234 CHECK(SameSymbol(symbol1, symbol2));
7236 SameSymbolHelper(context->GetIsolate(),
7237 "\360\220\220\205", // 4 byte encoding.
7238 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
7239 SameSymbolHelper(context->GetIsolate(),
7240 "\355\240\201\355\260\206", // 2 3-byte surrogates.
7241 "\360\220\220\206"); // 4 byte encoding.
7242 SameSymbolHelper(context->GetIsolate(),
7243 "x\360\220\220\205", // 4 byte encoding.
7244 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
7245 SameSymbolHelper(context->GetIsolate(),
7246 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
7247 "x\360\220\220\206"); // 4 byte encoding.
7249 "var sym0 = 'benedictus';"
7250 "var sym0b = 'S\303\270ren';"
7251 "var sym1 = '\355\240\201\355\260\207';"
7252 "var sym2 = '\360\220\220\210';"
7253 "var sym3 = 'x\355\240\201\355\260\207';"
7254 "var sym4 = 'x\360\220\220\210';"
7255 "if (sym1.length != 2) throw sym1;"
7256 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
7257 "if (sym2.length != 2) throw sym2;"
7258 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
7259 "if (sym3.length != 3) throw sym3;"
7260 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
7261 "if (sym4.length != 3) throw sym4;"
7262 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
7263 Handle<String> sym0 = v8::String::NewFromUtf8(
7264 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
7265 Handle<String> sym0b = v8::String::NewFromUtf8(
7266 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
7267 Handle<String> sym1 =
7268 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
7269 v8::String::kInternalizedString);
7270 Handle<String> sym2 =
7271 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
7272 v8::String::kInternalizedString);
7273 Handle<String> sym3 = v8::String::NewFromUtf8(
7274 context->GetIsolate(), "x\355\240\201\355\260\207",
7275 v8::String::kInternalizedString);
7276 Handle<String> sym4 =
7277 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
7278 v8::String::kInternalizedString);
7279 v8::Local<v8::Object> global = context->Global();
7280 Local<Value> s0 = global->Get(v8_str("sym0"));
7281 Local<Value> s0b = global->Get(v8_str("sym0b"));
7282 Local<Value> s1 = global->Get(v8_str("sym1"));
7283 Local<Value> s2 = global->Get(v8_str("sym2"));
7284 Local<Value> s3 = global->Get(v8_str("sym3"));
7285 Local<Value> s4 = global->Get(v8_str("sym4"));
7286 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
7287 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
7288 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
7289 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
7290 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
7291 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
7295 THREADED_TEST(ToArrayIndex) {
7296 LocalContext context;
7297 v8::Isolate* isolate = context->GetIsolate();
7298 v8::HandleScope scope(isolate);
7300 v8::Handle<String> str = v8_str("42");
7301 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
7302 CHECK(!index.IsEmpty());
7303 CHECK_EQ(42.0, index->Uint32Value());
7304 str = v8_str("42asdf");
7305 index = str->ToArrayIndex();
7306 CHECK(index.IsEmpty());
7307 str = v8_str("-42");
7308 index = str->ToArrayIndex();
7309 CHECK(index.IsEmpty());
7310 str = v8_str("4294967295");
7311 index = str->ToArrayIndex();
7312 CHECK(!index.IsEmpty());
7313 CHECK_EQ(4294967295.0, index->Uint32Value());
7314 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
7315 index = num->ToArrayIndex();
7316 CHECK(!index.IsEmpty());
7317 CHECK_EQ(1.0, index->Uint32Value());
7318 num = v8::Number::New(isolate, -1);
7319 index = num->ToArrayIndex();
7320 CHECK(index.IsEmpty());
7321 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
7322 index = obj->ToArrayIndex();
7323 CHECK(index.IsEmpty());
7327 THREADED_TEST(ErrorConstruction) {
7328 LocalContext context;
7329 v8::HandleScope scope(context->GetIsolate());
7331 v8::Handle<String> foo = v8_str("foo");
7332 v8::Handle<String> message = v8_str("message");
7333 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
7334 CHECK(range_error->IsObject());
7335 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
7336 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
7337 CHECK(reference_error->IsObject());
7338 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
7339 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
7340 CHECK(syntax_error->IsObject());
7341 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
7342 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
7343 CHECK(type_error->IsObject());
7344 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
7345 v8::Handle<Value> error = v8::Exception::Error(foo);
7346 CHECK(error->IsObject());
7347 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7351 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
7352 ApiTestFuzzer::Fuzz();
7353 v8::Handle<String> foo = v8_str("foo");
7354 v8::Handle<String> message = v8_str("message");
7355 v8::Handle<Value> error = v8::Exception::Error(foo);
7356 CHECK(error->IsObject());
7357 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
7358 info.GetIsolate()->ThrowException(error);
7359 info.GetReturnValue().SetUndefined();
7363 THREADED_TEST(ExceptionCreateMessage) {
7364 LocalContext context;
7365 v8::HandleScope scope(context->GetIsolate());
7366 v8::Handle<String> foo_str = v8_str("foo");
7367 v8::Handle<String> message_str = v8_str("message");
7369 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
7371 Local<v8::FunctionTemplate> fun =
7372 v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
7373 v8::Local<v8::Object> global = context->Global();
7374 global->Set(v8_str("throwV8Exception"), fun->GetFunction());
7379 " throwV8Exception();\n"
7382 CHECK(try_catch.HasCaught());
7384 v8::Handle<v8::Value> error = try_catch.Exception();
7385 CHECK(error->IsObject());
7386 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
7388 v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
7389 CHECK(!message.IsEmpty());
7390 CHECK_EQ(2, message->GetLineNumber());
7391 CHECK_EQ(2, message->GetStartColumn());
7393 v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
7394 CHECK(!stackTrace.IsEmpty());
7395 CHECK_EQ(2, stackTrace->GetFrameCount());
7397 stackTrace = v8::Exception::GetStackTrace(error);
7398 CHECK(!stackTrace.IsEmpty());
7399 CHECK_EQ(2, stackTrace->GetFrameCount());
7401 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
7403 // Now check message location when SetCaptureStackTraceForUncaughtExceptions
7409 " return throwV8Exception();\n"
7412 CHECK(try_catch.HasCaught());
7414 error = try_catch.Exception();
7415 CHECK(error->IsObject());
7416 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
7418 message = v8::Exception::CreateMessage(error);
7419 CHECK(!message.IsEmpty());
7420 CHECK_EQ(2, message->GetLineNumber());
7421 CHECK_EQ(9, message->GetStartColumn());
7423 // Should be empty stack trace.
7424 stackTrace = message->GetStackTrace();
7425 CHECK(stackTrace.IsEmpty());
7426 CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
7430 static void YGetter(Local<String> name,
7431 const v8::PropertyCallbackInfo<v8::Value>& info) {
7432 ApiTestFuzzer::Fuzz();
7433 info.GetReturnValue().Set(v8_num(10));
7437 static void YSetter(Local<String> name,
7439 const v8::PropertyCallbackInfo<void>& info) {
7440 Local<Object> this_obj = Local<Object>::Cast(info.This());
7441 if (this_obj->Has(name)) this_obj->Delete(name);
7442 this_obj->Set(name, value);
7446 THREADED_TEST(DeleteAccessor) {
7447 v8::Isolate* isolate = CcTest::isolate();
7448 v8::HandleScope scope(isolate);
7449 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7450 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
7451 LocalContext context;
7452 v8::Handle<v8::Object> holder = obj->NewInstance();
7453 context->Global()->Set(v8_str("holder"), holder);
7454 v8::Handle<Value> result = CompileRun(
7455 "holder.y = 11; holder.y = 12; holder.y");
7456 CHECK_EQ(12u, result->Uint32Value());
7460 THREADED_TEST(TypeSwitch) {
7461 v8::Isolate* isolate = CcTest::isolate();
7462 v8::HandleScope scope(isolate);
7463 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
7464 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
7465 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
7466 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
7467 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
7468 LocalContext context;
7469 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
7470 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
7471 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
7472 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
7473 for (int i = 0; i < 10; i++) {
7474 CHECK_EQ(0, type_switch->match(obj0));
7475 CHECK_EQ(1, type_switch->match(obj1));
7476 CHECK_EQ(2, type_switch->match(obj2));
7477 CHECK_EQ(3, type_switch->match(obj3));
7478 CHECK_EQ(3, type_switch->match(obj3));
7479 CHECK_EQ(2, type_switch->match(obj2));
7480 CHECK_EQ(1, type_switch->match(obj1));
7481 CHECK_EQ(0, type_switch->match(obj0));
7486 static int trouble_nesting = 0;
7487 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
7488 ApiTestFuzzer::Fuzz();
7491 // Call a JS function that throws an uncaught exception.
7492 Local<v8::Object> arg_this =
7493 args.GetIsolate()->GetCurrentContext()->Global();
7494 Local<Value> trouble_callee = (trouble_nesting == 3) ?
7495 arg_this->Get(v8_str("trouble_callee")) :
7496 arg_this->Get(v8_str("trouble_caller"));
7497 CHECK(trouble_callee->IsFunction());
7498 args.GetReturnValue().Set(
7499 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
7503 static int report_count = 0;
7504 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
7505 v8::Handle<Value>) {
7510 // Counts uncaught exceptions, but other tests running in parallel
7511 // also have uncaught exceptions.
7512 TEST(ApiUncaughtException) {
7515 v8::Isolate* isolate = env->GetIsolate();
7516 v8::HandleScope scope(isolate);
7517 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7519 Local<v8::FunctionTemplate> fun =
7520 v8::FunctionTemplate::New(isolate, TroubleCallback);
7521 v8::Local<v8::Object> global = env->Global();
7522 global->Set(v8_str("trouble"), fun->GetFunction());
7525 "function trouble_callee() {"
7529 "function trouble_caller() {"
7532 Local<Value> trouble = global->Get(v8_str("trouble"));
7533 CHECK(trouble->IsFunction());
7534 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
7535 CHECK(trouble_callee->IsFunction());
7536 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
7537 CHECK(trouble_caller->IsFunction());
7538 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
7539 CHECK_EQ(1, report_count);
7540 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7544 TEST(ApiUncaughtExceptionInObjectObserve) {
7545 v8::internal::FLAG_stack_size = 150;
7548 v8::Isolate* isolate = env->GetIsolate();
7549 v8::HandleScope scope(isolate);
7550 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
7553 "var observe_count = 0;"
7554 "function observer1() { ++observe_count; };"
7555 "function observer2() { ++observe_count; };"
7556 "function observer_throws() { throw new Error(); };"
7557 "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
7558 "Object.observe(obj, observer_throws.bind());"
7559 "Object.observe(obj, observer1);"
7560 "Object.observe(obj, stack_overflow);"
7561 "Object.observe(obj, observer2);"
7562 "Object.observe(obj, observer_throws.bind());"
7563 "obj.foo = 'bar';");
7564 CHECK_EQ(3, report_count);
7565 ExpectInt32("observe_count", 2);
7566 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
7570 static const char* script_resource_name = "ExceptionInNativeScript.js";
7571 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
7572 v8::Handle<Value>) {
7573 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
7574 CHECK(!name_val.IsEmpty() && name_val->IsString());
7575 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
7576 CHECK_EQ(0, strcmp(script_resource_name, *name));
7577 CHECK_EQ(3, message->GetLineNumber());
7578 v8::String::Utf8Value source_line(message->GetSourceLine());
7579 CHECK_EQ(0, strcmp(" new o.foo();", *source_line));
7583 TEST(ExceptionInNativeScript) {
7585 v8::Isolate* isolate = env->GetIsolate();
7586 v8::HandleScope scope(isolate);
7587 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
7589 Local<v8::FunctionTemplate> fun =
7590 v8::FunctionTemplate::New(isolate, TroubleCallback);
7591 v8::Local<v8::Object> global = env->Global();
7592 global->Set(v8_str("trouble"), fun->GetFunction());
7594 CompileRunWithOrigin(
7595 "function trouble() {\n"
7599 script_resource_name);
7600 Local<Value> trouble = global->Get(v8_str("trouble"));
7601 CHECK(trouble->IsFunction());
7602 Function::Cast(*trouble)->Call(global, 0, NULL);
7603 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
7607 TEST(CompilationErrorUsingTryCatchHandler) {
7609 v8::HandleScope scope(env->GetIsolate());
7610 v8::TryCatch try_catch;
7611 v8_compile("This doesn't &*&@#$&*^ compile.");
7612 CHECK(*try_catch.Exception());
7613 CHECK(try_catch.HasCaught());
7617 TEST(TryCatchFinallyUsingTryCatchHandler) {
7619 v8::HandleScope scope(env->GetIsolate());
7620 v8::TryCatch try_catch;
7621 CompileRun("try { throw ''; } catch (e) {}");
7622 CHECK(!try_catch.HasCaught());
7623 CompileRun("try { throw ''; } finally {}");
7624 CHECK(try_catch.HasCaught());
7628 "try { throw ''; } finally { return; }"
7630 CHECK(!try_catch.HasCaught());
7633 " { try { throw ''; } finally { throw 0; }"
7635 CHECK(try_catch.HasCaught());
7639 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
7640 v8::HandleScope scope(args.GetIsolate());
7641 CompileRun(args[0]->ToString(args.GetIsolate()));
7645 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
7646 v8::Isolate* isolate = CcTest::isolate();
7647 v8::HandleScope scope(isolate);
7648 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7649 templ->Set(v8_str("CEvaluate"),
7650 v8::FunctionTemplate::New(isolate, CEvaluate));
7651 LocalContext context(0, templ);
7652 v8::TryCatch try_catch;
7654 " CEvaluate('throw 1;');"
7657 CHECK(try_catch.HasCaught());
7658 CHECK(!try_catch.Message().IsEmpty());
7659 String::Utf8Value exception_value(try_catch.Exception());
7660 CHECK_EQ(0, strcmp(*exception_value, "1"));
7663 " CEvaluate('throw 1;');"
7667 CHECK(try_catch.HasCaught());
7668 CHECK(!try_catch.Message().IsEmpty());
7669 String::Utf8Value finally_exception_value(try_catch.Exception());
7670 CHECK_EQ(0, strcmp(*finally_exception_value, "2"));
7674 // For use within the TestSecurityHandler() test.
7675 static bool g_security_callback_result = false;
7676 static bool NamedSecurityTestCallback(Local<v8::Object> global,
7678 v8::AccessType type,
7679 Local<Value> data) {
7681 // Always allow read access.
7682 if (type == v8::ACCESS_GET)
7685 // Sometimes allow other access.
7686 return g_security_callback_result;
7690 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
7692 v8::AccessType type,
7693 Local<Value> data) {
7695 // Always allow read access.
7696 if (type == v8::ACCESS_GET)
7699 // Sometimes allow other access.
7700 return g_security_callback_result;
7704 // SecurityHandler can't be run twice
7705 TEST(SecurityHandler) {
7706 v8::Isolate* isolate = CcTest::isolate();
7707 v8::HandleScope scope0(isolate);
7708 v8::Handle<v8::ObjectTemplate> global_template =
7709 v8::ObjectTemplate::New(isolate);
7710 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
7711 IndexedSecurityTestCallback);
7712 // Create an environment
7713 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
7716 v8::Handle<v8::Object> global0 = context0->Global();
7717 v8::Handle<Script> script0 = v8_compile("foo = 111");
7719 global0->Set(v8_str("0"), v8_num(999));
7720 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
7721 CHECK_EQ(111, foo0->Int32Value());
7722 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
7723 CHECK_EQ(999, z0->Int32Value());
7725 // Create another environment, should fail security checks.
7726 v8::HandleScope scope1(isolate);
7728 v8::Handle<Context> context1 =
7729 Context::New(isolate, NULL, global_template);
7732 v8::Handle<v8::Object> global1 = context1->Global();
7733 global1->Set(v8_str("othercontext"), global0);
7734 // This set will fail the security check.
7735 v8::Handle<Script> script1 =
7736 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
7738 // This read will pass the security check.
7739 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
7740 CHECK_EQ(111, foo1->Int32Value());
7741 // This read will pass the security check.
7742 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
7743 CHECK_EQ(999, z1->Int32Value());
7745 // Create another environment, should pass security checks.
7746 { g_security_callback_result = true; // allow security handler to pass.
7747 v8::HandleScope scope2(isolate);
7748 LocalContext context2;
7749 v8::Handle<v8::Object> global2 = context2->Global();
7750 global2->Set(v8_str("othercontext"), global0);
7751 v8::Handle<Script> script2 =
7752 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
7754 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
7755 CHECK_EQ(333, foo2->Int32Value());
7756 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
7757 CHECK_EQ(888, z2->Int32Value());
7765 THREADED_TEST(SecurityChecks) {
7767 v8::HandleScope handle_scope(env1->GetIsolate());
7768 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7770 Local<Value> foo = v8_str("foo");
7771 Local<Value> bar = v8_str("bar");
7773 // Set to the same domain.
7774 env1->SetSecurityToken(foo);
7776 // Create a function in env1.
7777 CompileRun("spy=function(){return spy;}");
7778 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
7779 CHECK(spy->IsFunction());
7781 // Create another function accessing global objects.
7782 CompileRun("spy2=function(){return new this.Array();}");
7783 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
7784 CHECK(spy2->IsFunction());
7786 // Switch to env2 in the same domain and invoke spy on env2.
7788 env2->SetSecurityToken(foo);
7790 Context::Scope scope_env2(env2);
7791 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
7792 CHECK(result->IsFunction());
7796 env2->SetSecurityToken(bar);
7797 Context::Scope scope_env2(env2);
7799 // Call cross_domain_call, it should throw an exception
7800 v8::TryCatch try_catch;
7801 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
7802 CHECK(try_catch.HasCaught());
7807 // Regression test case for issue 1183439.
7808 THREADED_TEST(SecurityChecksForPrototypeChain) {
7809 LocalContext current;
7810 v8::HandleScope scope(current->GetIsolate());
7811 v8::Handle<Context> other = Context::New(current->GetIsolate());
7813 // Change context to be able to get to the Object function in the
7814 // other context without hitting the security checks.
7815 v8::Local<Value> other_object;
7816 { Context::Scope scope(other);
7817 other_object = other->Global()->Get(v8_str("Object"));
7818 other->Global()->Set(v8_num(42), v8_num(87));
7821 current->Global()->Set(v8_str("other"), other->Global());
7822 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
7824 // Make sure the security check fails here and we get an undefined
7825 // result instead of getting the Object function. Repeat in a loop
7826 // to make sure to exercise the IC code.
7827 v8::Local<Script> access_other0 = v8_compile("other.Object");
7828 v8::Local<Script> access_other1 = v8_compile("other[42]");
7829 for (int i = 0; i < 5; i++) {
7830 CHECK(access_other0->Run().IsEmpty());
7831 CHECK(access_other1->Run().IsEmpty());
7834 // Create an object that has 'other' in its prototype chain and make
7835 // sure we cannot access the Object function indirectly through
7836 // that. Repeat in a loop to make sure to exercise the IC code.
7837 v8_compile("function F() { };"
7838 "F.prototype = other;"
7839 "var f = new F();")->Run();
7840 v8::Local<Script> access_f0 = v8_compile("f.Object");
7841 v8::Local<Script> access_f1 = v8_compile("f[42]");
7842 for (int j = 0; j < 5; j++) {
7843 CHECK(access_f0->Run().IsEmpty());
7844 CHECK(access_f1->Run().IsEmpty());
7847 // Now it gets hairy: Set the prototype for the other global object
7848 // to be the current global object. The prototype chain for 'f' now
7849 // goes through 'other' but ends up in the current global object.
7850 { Context::Scope scope(other);
7851 other->Global()->Set(v8_str("__proto__"), current->Global());
7853 // Set a named and an index property on the current global
7854 // object. To force the lookup to go through the other global object,
7855 // the properties must not exist in the other global object.
7856 current->Global()->Set(v8_str("foo"), v8_num(100));
7857 current->Global()->Set(v8_num(99), v8_num(101));
7858 // Try to read the properties from f and make sure that the access
7859 // gets stopped by the security checks on the other global object.
7860 Local<Script> access_f2 = v8_compile("f.foo");
7861 Local<Script> access_f3 = v8_compile("f[99]");
7862 for (int k = 0; k < 5; k++) {
7863 CHECK(access_f2->Run().IsEmpty());
7864 CHECK(access_f3->Run().IsEmpty());
7869 static bool named_security_check_with_gc_called;
7871 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
7873 v8::AccessType type,
7874 Local<Value> data) {
7875 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7876 named_security_check_with_gc_called = true;
7881 static bool indexed_security_check_with_gc_called;
7883 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
7885 v8::AccessType type,
7886 Local<Value> data) {
7887 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7888 indexed_security_check_with_gc_called = true;
7893 TEST(SecurityTestGCAllowed) {
7894 v8::Isolate* isolate = CcTest::isolate();
7895 v8::HandleScope handle_scope(isolate);
7896 v8::Handle<v8::ObjectTemplate> object_template =
7897 v8::ObjectTemplate::New(isolate);
7898 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
7899 IndexedSecurityTestCallbackWithGC);
7901 v8::Handle<Context> context = Context::New(isolate);
7902 v8::Context::Scope context_scope(context);
7904 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
7906 named_security_check_with_gc_called = false;
7907 CompileRun("obj.foo = new String(1001);");
7908 CHECK(named_security_check_with_gc_called);
7910 indexed_security_check_with_gc_called = false;
7911 CompileRun("obj[0] = new String(1002);");
7912 CHECK(indexed_security_check_with_gc_called);
7914 named_security_check_with_gc_called = false;
7915 CHECK(CompileRun("obj.foo")->ToString(isolate)->Equals(v8_str("1001")));
7916 CHECK(named_security_check_with_gc_called);
7918 indexed_security_check_with_gc_called = false;
7919 CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
7920 CHECK(indexed_security_check_with_gc_called);
7924 THREADED_TEST(CrossDomainDelete) {
7926 v8::HandleScope handle_scope(env1->GetIsolate());
7927 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7929 Local<Value> foo = v8_str("foo");
7930 Local<Value> bar = v8_str("bar");
7932 // Set to the same domain.
7933 env1->SetSecurityToken(foo);
7934 env2->SetSecurityToken(foo);
7936 env1->Global()->Set(v8_str("prop"), v8_num(3));
7937 env2->Global()->Set(v8_str("env1"), env1->Global());
7939 // Change env2 to a different domain and delete env1.prop.
7940 env2->SetSecurityToken(bar);
7942 Context::Scope scope_env2(env2);
7943 Local<Value> result =
7944 CompileRun("delete env1.prop");
7945 CHECK(result.IsEmpty());
7948 // Check that env1.prop still exists.
7949 Local<Value> v = env1->Global()->Get(v8_str("prop"));
7950 CHECK(v->IsNumber());
7951 CHECK_EQ(3, v->Int32Value());
7955 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
7957 v8::HandleScope handle_scope(env1->GetIsolate());
7958 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7960 Local<Value> foo = v8_str("foo");
7961 Local<Value> bar = v8_str("bar");
7963 // Set to the same domain.
7964 env1->SetSecurityToken(foo);
7965 env2->SetSecurityToken(foo);
7967 env1->Global()->Set(v8_str("prop"), v8_num(3));
7968 env2->Global()->Set(v8_str("env1"), env1->Global());
7970 // env1.prop is enumerable in env2.
7971 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
7973 Context::Scope scope_env2(env2);
7974 Local<Value> result = CompileRun(test);
7975 CHECK(result->IsTrue());
7978 // Change env2 to a different domain and test again.
7979 env2->SetSecurityToken(bar);
7981 Context::Scope scope_env2(env2);
7982 Local<Value> result = CompileRun(test);
7983 CHECK(result.IsEmpty());
7988 THREADED_TEST(CrossDomainForIn) {
7990 v8::HandleScope handle_scope(env1->GetIsolate());
7991 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
7993 Local<Value> foo = v8_str("foo");
7994 Local<Value> bar = v8_str("bar");
7996 // Set to the same domain.
7997 env1->SetSecurityToken(foo);
7998 env2->SetSecurityToken(foo);
8000 env1->Global()->Set(v8_str("prop"), v8_num(3));
8001 env2->Global()->Set(v8_str("env1"), env1->Global());
8003 // Change env2 to a different domain and set env1's global object
8004 // as the __proto__ of an object in env2 and enumerate properties
8005 // in for-in. It shouldn't enumerate properties on env1's global
8007 env2->SetSecurityToken(bar);
8009 Context::Scope scope_env2(env2);
8010 Local<Value> result = CompileRun(
8012 " var obj = { '__proto__': env1 };"
8014 " for (var p in obj) {"
8015 " if (p == 'prop') return false;"
8022 CHECK(result->IsTrue());
8027 TEST(ContextDetachGlobal) {
8029 v8::HandleScope handle_scope(env1->GetIsolate());
8030 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8032 Local<v8::Object> global1 = env1->Global();
8034 Local<Value> foo = v8_str("foo");
8036 // Set to the same domain.
8037 env1->SetSecurityToken(foo);
8038 env2->SetSecurityToken(foo);
8043 // Create a function in env2 and add a reference to it in env1.
8044 Local<v8::Object> global2 = env2->Global();
8045 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
8046 CompileRun("function getProp() {return prop;}");
8048 env1->Global()->Set(v8_str("getProp"),
8049 global2->Get(v8_str("getProp")));
8051 // Detach env2's global, and reuse the global object of env2
8053 env2->DetachGlobal();
8055 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8057 v8::Handle<v8::ObjectTemplate>(),
8059 env3->SetSecurityToken(v8_str("bar"));
8062 Local<v8::Object> global3 = env3->Global();
8063 CHECK(global2->Equals(global3));
8064 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
8065 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
8066 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
8067 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
8070 // Call getProp in env1, and it should return the value 1
8072 Local<Value> get_prop = global1->Get(v8_str("getProp"));
8073 CHECK(get_prop->IsFunction());
8074 v8::TryCatch try_catch;
8075 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
8076 CHECK(!try_catch.HasCaught());
8077 CHECK_EQ(1, r->Int32Value());
8080 // Check that env3 is not accessible from env1
8082 Local<Value> r = global3->Get(v8_str("prop2"));
8088 TEST(DetachGlobal) {
8090 v8::HandleScope scope(env1->GetIsolate());
8092 // Create second environment.
8093 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
8095 Local<Value> foo = v8_str("foo");
8097 // Set same security token for env1 and env2.
8098 env1->SetSecurityToken(foo);
8099 env2->SetSecurityToken(foo);
8101 // Create a property on the global object in env2.
8103 v8::Context::Scope scope(env2);
8104 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
8107 // Create a reference to env2 global from env1 global.
8108 env1->Global()->Set(v8_str("other"), env2->Global());
8110 // Check that we have access to other.p in env2 from env1.
8111 Local<Value> result = CompileRun("other.p");
8112 CHECK(result->IsInt32());
8113 CHECK_EQ(42, result->Int32Value());
8115 // Hold on to global from env2 and detach global from env2.
8116 Local<v8::Object> global2 = env2->Global();
8117 env2->DetachGlobal();
8119 // Check that the global has been detached. No other.p property can
8121 result = CompileRun("other.p");
8122 CHECK(result.IsEmpty());
8124 // Reuse global2 for env3.
8125 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
8127 v8::Handle<v8::ObjectTemplate>(),
8129 CHECK(global2->Equals(env3->Global()));
8131 // Start by using the same security token for env3 as for env1 and env2.
8132 env3->SetSecurityToken(foo);
8134 // Create a property on the global object in env3.
8136 v8::Context::Scope scope(env3);
8137 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
8140 // Check that other.p is now the property in env3 and that we have access.
8141 result = CompileRun("other.p");
8142 CHECK(result->IsInt32());
8143 CHECK_EQ(24, result->Int32Value());
8145 // Change security token for env3 to something different from env1 and env2.
8146 env3->SetSecurityToken(v8_str("bar"));
8148 // Check that we do not have access to other.p in env1. |other| is now
8149 // the global object for env3 which has a different security token,
8150 // so access should be blocked.
8151 result = CompileRun("other.p");
8152 CHECK(result.IsEmpty());
8156 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
8157 info.GetReturnValue().Set(
8158 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
8162 TEST(DetachedAccesses) {
8164 v8::HandleScope scope(env1->GetIsolate());
8166 // Create second environment.
8167 Local<ObjectTemplate> inner_global_template =
8168 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
8169 inner_global_template ->SetAccessorProperty(
8170 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
8171 v8::Local<Context> env2 =
8172 Context::New(env1->GetIsolate(), NULL, inner_global_template);
8174 Local<Value> foo = v8_str("foo");
8176 // Set same security token for env1 and env2.
8177 env1->SetSecurityToken(foo);
8178 env2->SetSecurityToken(foo);
8180 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
8183 v8::Context::Scope scope(env2);
8184 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
8186 "function bound_x() { return x; }"
8187 "function get_x() { return this.x; }"
8188 "function get_x_w() { return (function() {return this.x;})(); }");
8189 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
8190 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
8191 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
8192 env1->Global()->Set(
8194 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
8197 Local<Object> env2_global = env2->Global();
8198 env2_global->TurnOnAccessCheck();
8199 env2->DetachGlobal();
8201 Local<Value> result;
8202 result = CompileRun("bound_x()");
8203 CHECK(v8_str("env2_x")->Equals(result));
8204 result = CompileRun("get_x()");
8205 CHECK(result.IsEmpty());
8206 result = CompileRun("get_x_w()");
8207 CHECK(result.IsEmpty());
8208 result = CompileRun("this_x()");
8209 CHECK(v8_str("env2_x")->Equals(result));
8211 // Reattach env2's proxy
8212 env2 = Context::New(env1->GetIsolate(),
8214 v8::Handle<v8::ObjectTemplate>(),
8216 env2->SetSecurityToken(foo);
8218 v8::Context::Scope scope(env2);
8219 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
8220 env2->Global()->Set(v8_str("env1"), env1->Global());
8221 result = CompileRun(
8223 "for (var i = 0; i < 4; i++ ) {"
8224 " results.push(env1.bound_x());"
8225 " results.push(env1.get_x());"
8226 " results.push(env1.get_x_w());"
8227 " results.push(env1.this_x());"
8230 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8231 CHECK_EQ(16u, results->Length());
8232 for (int i = 0; i < 16; i += 4) {
8233 CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8234 CHECK(v8_str("env1_x")->Equals(results->Get(i + 1)));
8235 CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8236 CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8240 result = CompileRun(
8242 "for (var i = 0; i < 4; i++ ) {"
8243 " results.push(bound_x());"
8244 " results.push(get_x());"
8245 " results.push(get_x_w());"
8246 " results.push(this_x());"
8249 Local<v8::Array> results = Local<v8::Array>::Cast(result);
8250 CHECK_EQ(16u, results->Length());
8251 for (int i = 0; i < 16; i += 4) {
8252 CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8253 CHECK(v8_str("env3_x")->Equals(results->Get(i + 1)));
8254 CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8255 CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8258 result = CompileRun(
8260 "for (var i = 0; i < 4; i++ ) {"
8261 " results.push(this.bound_x());"
8262 " results.push(this.get_x());"
8263 " results.push(this.get_x_w());"
8264 " results.push(this.this_x());"
8267 results = Local<v8::Array>::Cast(result);
8268 CHECK_EQ(16u, results->Length());
8269 for (int i = 0; i < 16; i += 4) {
8270 CHECK(v8_str("env2_x")->Equals(results->Get(i + 0)));
8271 CHECK(v8_str("env1_x")->Equals(results->Get(i + 1)));
8272 CHECK(v8_str("env3_x")->Equals(results->Get(i + 2)));
8273 CHECK(v8_str("env2_x")->Equals(results->Get(i + 3)));
8278 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
8279 static bool NamedAccessBlocker(Local<v8::Object> global,
8281 v8::AccessType type,
8282 Local<Value> data) {
8283 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8284 allowed_access_type[type];
8288 static bool IndexedAccessBlocker(Local<v8::Object> global,
8290 v8::AccessType type,
8291 Local<Value> data) {
8292 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
8293 allowed_access_type[type];
8297 static int g_echo_value = -1;
8300 static void EchoGetter(
8302 const v8::PropertyCallbackInfo<v8::Value>& info) {
8303 info.GetReturnValue().Set(v8_num(g_echo_value));
8307 static void EchoSetter(Local<String> name,
8309 const v8::PropertyCallbackInfo<void>&) {
8310 if (value->IsNumber())
8311 g_echo_value = value->Int32Value();
8315 static void UnreachableGetter(
8317 const v8::PropertyCallbackInfo<v8::Value>& info) {
8318 CHECK(false); // This function should not be called..
8322 static void UnreachableSetter(Local<String>,
8324 const v8::PropertyCallbackInfo<void>&) {
8325 CHECK(false); // This function should nto be called.
8329 static void UnreachableFunction(
8330 const v8::FunctionCallbackInfo<v8::Value>& info) {
8331 CHECK(false); // This function should not be called..
8335 TEST(AccessControl) {
8336 v8::Isolate* isolate = CcTest::isolate();
8337 v8::HandleScope handle_scope(isolate);
8338 v8::Handle<v8::ObjectTemplate> global_template =
8339 v8::ObjectTemplate::New(isolate);
8341 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8342 IndexedAccessBlocker);
8344 // Add an accessor accessible by cross-domain JS code.
8345 global_template->SetAccessor(
8346 v8_str("accessible_prop"),
8347 EchoGetter, EchoSetter,
8348 v8::Handle<Value>(),
8349 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8352 // Add an accessor that is not accessible by cross-domain JS code.
8353 global_template->SetAccessor(v8_str("blocked_prop"),
8354 UnreachableGetter, UnreachableSetter,
8355 v8::Handle<Value>(),
8358 global_template->SetAccessorProperty(
8359 v8_str("blocked_js_prop"),
8360 v8::FunctionTemplate::New(isolate, UnreachableFunction),
8361 v8::FunctionTemplate::New(isolate, UnreachableFunction),
8365 // Create an environment
8366 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8369 v8::Handle<v8::Object> global0 = context0->Global();
8371 // Define a property with JS getter and setter.
8373 "function getter() { return 'getter'; };\n"
8374 "function setter() { return 'setter'; }\n"
8375 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
8377 Local<Value> getter = global0->Get(v8_str("getter"));
8378 Local<Value> setter = global0->Get(v8_str("setter"));
8380 // And define normal element.
8381 global0->Set(239, v8_str("239"));
8383 // Define an element with JS getter and setter.
8385 "function el_getter() { return 'el_getter'; };\n"
8386 "function el_setter() { return 'el_setter'; };\n"
8387 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
8389 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
8390 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
8392 v8::HandleScope scope1(isolate);
8394 v8::Local<Context> context1 = Context::New(isolate);
8397 v8::Handle<v8::Object> global1 = context1->Global();
8398 global1->Set(v8_str("other"), global0);
8400 // Access blocked property.
8401 CompileRun("other.blocked_prop = 1");
8403 CHECK(CompileRun("other.blocked_prop").IsEmpty());
8404 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
8407 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
8409 // Access blocked element.
8410 CHECK(CompileRun("other[239] = 1").IsEmpty());
8412 CHECK(CompileRun("other[239]").IsEmpty());
8413 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
8414 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
8416 // Enable ACCESS_HAS
8417 allowed_access_type[v8::ACCESS_HAS] = true;
8418 CHECK(CompileRun("other[239]").IsEmpty());
8419 // ... and now we can get the descriptor...
8420 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
8422 // ... and enumerate the property.
8423 ExpectTrue("propertyIsEnumerable.call(other, '239')");
8424 allowed_access_type[v8::ACCESS_HAS] = false;
8426 // Access a property with JS accessor.
8427 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
8429 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
8430 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
8433 // Enable both ACCESS_HAS and ACCESS_GET.
8434 allowed_access_type[v8::ACCESS_HAS] = true;
8435 allowed_access_type[v8::ACCESS_GET] = true;
8437 ExpectString("other.js_accessor_p", "getter");
8439 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
8441 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
8443 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
8445 allowed_access_type[v8::ACCESS_HAS] = false;
8446 allowed_access_type[v8::ACCESS_GET] = false;
8448 // Access an element with JS accessor.
8449 CHECK(CompileRun("other[42] = 2").IsEmpty());
8451 CHECK(CompileRun("other[42]").IsEmpty());
8452 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
8454 // Enable both ACCESS_HAS and ACCESS_GET.
8455 allowed_access_type[v8::ACCESS_HAS] = true;
8456 allowed_access_type[v8::ACCESS_GET] = true;
8458 ExpectString("other[42]", "el_getter");
8459 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
8460 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
8461 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
8463 allowed_access_type[v8::ACCESS_HAS] = false;
8464 allowed_access_type[v8::ACCESS_GET] = false;
8466 v8::Handle<Value> value;
8468 // Access accessible property
8469 value = CompileRun("other.accessible_prop = 3");
8470 CHECK(value->IsNumber());
8471 CHECK_EQ(3, value->Int32Value());
8472 CHECK_EQ(3, g_echo_value);
8474 value = CompileRun("other.accessible_prop");
8475 CHECK(value->IsNumber());
8476 CHECK_EQ(3, value->Int32Value());
8479 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
8480 CHECK(value->IsNumber());
8481 CHECK_EQ(3, value->Int32Value());
8483 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
8484 CHECK(value->IsTrue());
8486 // Enumeration doesn't enumerate accessors from inaccessible objects in
8487 // the prototype chain even if the accessors are in themselves accessible.
8490 " var obj = { '__proto__': other };"
8492 " for (var p in obj) {"
8493 " if (p == 'accessible_prop' ||"
8494 " p == 'blocked_js_prop' ||"
8495 " p == 'blocked_js_prop') {"
8504 CHECK(value->IsTrue());
8511 TEST(AccessControlES5) {
8512 v8::Isolate* isolate = CcTest::isolate();
8513 v8::HandleScope handle_scope(isolate);
8514 v8::Handle<v8::ObjectTemplate> global_template =
8515 v8::ObjectTemplate::New(isolate);
8517 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
8518 IndexedAccessBlocker);
8520 // Add accessible accessor.
8521 global_template->SetAccessor(
8522 v8_str("accessible_prop"),
8523 EchoGetter, EchoSetter,
8524 v8::Handle<Value>(),
8525 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
8528 // Add an accessor that is not accessible by cross-domain JS code.
8529 global_template->SetAccessor(v8_str("blocked_prop"),
8530 UnreachableGetter, UnreachableSetter,
8531 v8::Handle<Value>(),
8534 // Create an environment
8535 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8538 v8::Handle<v8::Object> global0 = context0->Global();
8540 v8::Local<Context> context1 = Context::New(isolate);
8542 v8::Handle<v8::Object> global1 = context1->Global();
8543 global1->Set(v8_str("other"), global0);
8545 // Regression test for issue 1154.
8546 CHECK(CompileRun("Object.keys(other)").IsEmpty());
8547 CHECK(CompileRun("other.blocked_prop").IsEmpty());
8549 // Regression test for issue 1027.
8550 CompileRun("Object.defineProperty(\n"
8551 " other, 'blocked_prop', {configurable: false})");
8552 CHECK(CompileRun("other.blocked_prop").IsEmpty());
8553 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
8556 // Regression test for issue 1171.
8557 ExpectTrue("Object.isExtensible(other)");
8558 CompileRun("Object.preventExtensions(other)");
8559 ExpectTrue("Object.isExtensible(other)");
8561 // Object.seal and Object.freeze.
8562 CompileRun("Object.freeze(other)");
8563 ExpectTrue("Object.isExtensible(other)");
8565 CompileRun("Object.seal(other)");
8566 ExpectTrue("Object.isExtensible(other)");
8568 // Regression test for issue 1250.
8569 // Make sure that we can set the accessible accessors value using normal
8571 CompileRun("other.accessible_prop = 42");
8572 CHECK_EQ(42, g_echo_value);
8574 v8::Handle<Value> value;
8575 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
8576 value = CompileRun("other.accessible_prop == 42");
8577 CHECK(value->IsTrue());
8581 static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
8582 v8::AccessType type, Local<Value> data) {
8587 static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
8588 v8::AccessType type, Local<Value> data) {
8593 THREADED_TEST(AccessControlGetOwnPropertyNames) {
8594 v8::Isolate* isolate = CcTest::isolate();
8595 v8::HandleScope handle_scope(isolate);
8596 v8::Handle<v8::ObjectTemplate> obj_template =
8597 v8::ObjectTemplate::New(isolate);
8599 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
8600 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
8601 BlockEverythingIndexed);
8603 // Create an environment
8604 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
8607 v8::Handle<v8::Object> global0 = context0->Global();
8609 v8::HandleScope scope1(CcTest::isolate());
8611 v8::Local<Context> context1 = Context::New(isolate);
8614 v8::Handle<v8::Object> global1 = context1->Global();
8615 global1->Set(v8_str("other"), global0);
8616 global1->Set(v8_str("object"), obj_template->NewInstance());
8618 v8::Handle<Value> value;
8620 // Attempt to get the property names of the other global object and
8621 // of an object that requires access checks. Accessing the other
8622 // global object should be blocked by access checks on the global
8623 // proxy object. Accessing the object that requires access checks
8624 // is blocked by the access checks on the object itself.
8625 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
8626 CHECK(value.IsEmpty());
8628 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
8629 CHECK(value.IsEmpty());
8636 TEST(SuperAccessControl) {
8637 i::FLAG_allow_natives_syntax = true;
8638 i::FLAG_harmony_classes = true;
8639 i::FLAG_harmony_object_literals = true;
8640 v8::Isolate* isolate = CcTest::isolate();
8641 v8::HandleScope handle_scope(isolate);
8642 v8::Handle<v8::ObjectTemplate> obj_template =
8643 v8::ObjectTemplate::New(isolate);
8644 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
8645 BlockEverythingIndexed);
8647 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
8650 v8::TryCatch try_catch;
8652 "var f = { m() { return super.hasOwnProperty; } }.m;"
8653 "var m = %ToMethod(f, prohibited);"
8655 CHECK(try_catch.HasCaught());
8659 v8::TryCatch try_catch;
8661 "var f = {m() { return super[42]; } }.m;"
8662 "var m = %ToMethod(f, prohibited);"
8664 CHECK(try_catch.HasCaught());
8668 v8::TryCatch try_catch;
8670 "var f = {m() { super.hasOwnProperty = function () {}; } }.m;"
8671 "var m = %ToMethod(f, prohibited);"
8673 CHECK(try_catch.HasCaught());
8677 v8::TryCatch try_catch;
8679 "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
8683 " super.x = function () {};"
8686 "var m = %ToMethod(f, prohibited);"
8688 CHECK(try_catch.HasCaught());
8693 static void ConstTenGetter(Local<String> name,
8694 const v8::PropertyCallbackInfo<v8::Value>& info) {
8695 info.GetReturnValue().Set(v8_num(10));
8699 THREADED_TEST(CrossDomainAccessors) {
8700 v8::Isolate* isolate = CcTest::isolate();
8701 v8::HandleScope handle_scope(isolate);
8703 v8::Handle<v8::FunctionTemplate> func_template =
8704 v8::FunctionTemplate::New(isolate);
8706 v8::Handle<v8::ObjectTemplate> global_template =
8707 func_template->InstanceTemplate();
8709 v8::Handle<v8::ObjectTemplate> proto_template =
8710 func_template->PrototypeTemplate();
8712 // Add an accessor to proto that's accessible by cross-domain JS code.
8713 proto_template->SetAccessor(v8_str("accessible"),
8715 v8::Handle<Value>(),
8718 // Add an accessor that is not accessible by cross-domain JS code.
8719 global_template->SetAccessor(v8_str("unreachable"),
8720 UnreachableGetter, 0,
8721 v8::Handle<Value>(),
8724 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
8727 Local<v8::Object> global = context0->Global();
8728 // Add a normal property that shadows 'accessible'
8729 global->Set(v8_str("accessible"), v8_num(11));
8731 // Enter a new context.
8732 v8::HandleScope scope1(CcTest::isolate());
8733 v8::Local<Context> context1 = Context::New(isolate);
8736 v8::Handle<v8::Object> global1 = context1->Global();
8737 global1->Set(v8_str("other"), global);
8739 // Should return 10, instead of 11
8740 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
8741 CHECK(value->IsNumber());
8742 CHECK_EQ(10, value->Int32Value());
8744 value = v8_compile("other.unreachable")->Run();
8745 CHECK(value.IsEmpty());
8752 static int named_access_count = 0;
8753 static int indexed_access_count = 0;
8755 static bool NamedAccessCounter(Local<v8::Object> global,
8757 v8::AccessType type,
8758 Local<Value> data) {
8759 named_access_count++;
8764 static bool IndexedAccessCounter(Local<v8::Object> global,
8766 v8::AccessType type,
8767 Local<Value> data) {
8768 indexed_access_count++;
8773 // This one is too easily disturbed by other tests.
8774 TEST(AccessControlIC) {
8775 named_access_count = 0;
8776 indexed_access_count = 0;
8778 v8::Isolate* isolate = CcTest::isolate();
8779 v8::HandleScope handle_scope(isolate);
8781 // Create an environment.
8782 v8::Local<Context> context0 = Context::New(isolate);
8785 // Create an object that requires access-check functions to be
8786 // called for cross-domain access.
8787 v8::Handle<v8::ObjectTemplate> object_template =
8788 v8::ObjectTemplate::New(isolate);
8789 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
8790 IndexedAccessCounter);
8791 Local<v8::Object> object = object_template->NewInstance();
8793 v8::HandleScope scope1(isolate);
8795 // Create another environment.
8796 v8::Local<Context> context1 = Context::New(isolate);
8799 // Make easy access to the object from the other environment.
8800 v8::Handle<v8::Object> global1 = context1->Global();
8801 global1->Set(v8_str("obj"), object);
8803 v8::Handle<Value> value;
8805 // Check that the named access-control function is called every time.
8806 CompileRun("function testProp(obj) {"
8807 " for (var i = 0; i < 10; i++) obj.prop = 1;"
8808 " for (var j = 0; j < 10; j++) obj.prop;"
8811 value = CompileRun("testProp(obj)");
8812 CHECK(value->IsNumber());
8813 CHECK_EQ(1, value->Int32Value());
8814 CHECK_EQ(21, named_access_count);
8816 // Check that the named access-control function is called every time.
8817 CompileRun("var p = 'prop';"
8818 "function testKeyed(obj) {"
8819 " for (var i = 0; i < 10; i++) obj[p] = 1;"
8820 " for (var j = 0; j < 10; j++) obj[p];"
8823 // Use obj which requires access checks. No inline caching is used
8825 value = CompileRun("testKeyed(obj)");
8826 CHECK(value->IsNumber());
8827 CHECK_EQ(1, value->Int32Value());
8828 CHECK_EQ(42, named_access_count);
8829 // Force the inline caches into generic state and try again.
8830 CompileRun("testKeyed({ a: 0 })");
8831 CompileRun("testKeyed({ b: 0 })");
8832 value = CompileRun("testKeyed(obj)");
8833 CHECK(value->IsNumber());
8834 CHECK_EQ(1, value->Int32Value());
8835 CHECK_EQ(63, named_access_count);
8837 // Check that the indexed access-control function is called every time.
8838 CompileRun("function testIndexed(obj) {"
8839 " for (var i = 0; i < 10; i++) obj[0] = 1;"
8840 " for (var j = 0; j < 10; j++) obj[0];"
8843 value = CompileRun("testIndexed(obj)");
8844 CHECK(value->IsNumber());
8845 CHECK_EQ(1, value->Int32Value());
8846 CHECK_EQ(21, indexed_access_count);
8847 // Force the inline caches into generic state.
8848 CompileRun("testIndexed(new Array(1))");
8849 // Test that the indexed access check is called.
8850 value = CompileRun("testIndexed(obj)");
8851 CHECK(value->IsNumber());
8852 CHECK_EQ(1, value->Int32Value());
8853 CHECK_EQ(42, indexed_access_count);
8855 // Check that the named access check is called when invoking
8856 // functions on an object that requires access checks.
8857 CompileRun("obj.f = function() {}");
8858 CompileRun("function testCallNormal(obj) {"
8859 " for (var i = 0; i < 10; i++) obj.f();"
8861 CompileRun("testCallNormal(obj)");
8862 CHECK_EQ(74, named_access_count);
8864 // Force obj into slow case.
8865 value = CompileRun("delete obj.prop");
8866 CHECK(value->BooleanValue());
8867 // Force inline caches into dictionary probing mode.
8868 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
8869 // Test that the named access check is called.
8870 value = CompileRun("testProp(obj);");
8871 CHECK(value->IsNumber());
8872 CHECK_EQ(1, value->Int32Value());
8873 CHECK_EQ(96, named_access_count);
8875 // Force the call inline cache into dictionary probing mode.
8876 CompileRun("o.f = function() {}; testCallNormal(o)");
8877 // Test that the named access check is still called for each
8878 // invocation of the function.
8879 value = CompileRun("testCallNormal(obj)");
8880 CHECK_EQ(106, named_access_count);
8887 static bool NamedAccessFlatten(Local<v8::Object> global,
8889 v8::AccessType type,
8890 Local<Value> data) {
8894 CHECK(name->IsString());
8896 memset(buf, 0x1, sizeof(buf));
8897 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8902 memset(buf, 0x1, sizeof(buf));
8903 len = name.As<String>()->Write(buf2);
8910 static bool IndexedAccessFlatten(Local<v8::Object> global,
8912 v8::AccessType type,
8913 Local<Value> data) {
8918 // Regression test. In access checks, operations that may cause
8919 // garbage collection are not allowed. It used to be the case that
8920 // using the Write operation on a string could cause a garbage
8921 // collection due to flattening of the string. This is no longer the
8923 THREADED_TEST(AccessControlFlatten) {
8924 named_access_count = 0;
8925 indexed_access_count = 0;
8927 v8::Isolate* isolate = CcTest::isolate();
8928 v8::HandleScope handle_scope(isolate);
8930 // Create an environment.
8931 v8::Local<Context> context0 = Context::New(isolate);
8934 // Create an object that requires access-check functions to be
8935 // called for cross-domain access.
8936 v8::Handle<v8::ObjectTemplate> object_template =
8937 v8::ObjectTemplate::New(isolate);
8938 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
8939 IndexedAccessFlatten);
8940 Local<v8::Object> object = object_template->NewInstance();
8942 v8::HandleScope scope1(isolate);
8944 // Create another environment.
8945 v8::Local<Context> context1 = Context::New(isolate);
8948 // Make easy access to the object from the other environment.
8949 v8::Handle<v8::Object> global1 = context1->Global();
8950 global1->Set(v8_str("obj"), object);
8952 v8::Handle<Value> value;
8954 value = v8_compile("var p = 'as' + 'df';")->Run();
8955 value = v8_compile("obj[p];")->Run();
8962 THREADED_TEST(Version) { v8::V8::GetVersion(); }
8965 static void InstanceFunctionCallback(
8966 const v8::FunctionCallbackInfo<v8::Value>& args) {
8967 ApiTestFuzzer::Fuzz();
8968 args.GetReturnValue().Set(v8_num(12));
8972 THREADED_TEST(InstanceProperties) {
8973 LocalContext context;
8974 v8::Isolate* isolate = context->GetIsolate();
8975 v8::HandleScope handle_scope(isolate);
8977 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
8978 Local<ObjectTemplate> instance = t->InstanceTemplate();
8980 instance->Set(v8_str("x"), v8_num(42));
8981 instance->Set(v8_str("f"),
8982 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
8984 Local<Value> o = t->GetFunction()->NewInstance();
8986 context->Global()->Set(v8_str("i"), o);
8987 Local<Value> value = CompileRun("i.x");
8988 CHECK_EQ(42, value->Int32Value());
8990 value = CompileRun("i.f()");
8991 CHECK_EQ(12, value->Int32Value());
8995 static void GlobalObjectInstancePropertiesGet(
8996 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
8997 ApiTestFuzzer::Fuzz();
9001 THREADED_TEST(GlobalObjectInstanceProperties) {
9002 v8::Isolate* isolate = CcTest::isolate();
9003 v8::HandleScope handle_scope(isolate);
9005 Local<Value> global_object;
9007 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9008 t->InstanceTemplate()->SetHandler(
9009 v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
9010 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9011 instance_template->Set(v8_str("x"), v8_num(42));
9012 instance_template->Set(v8_str("f"),
9013 v8::FunctionTemplate::New(isolate,
9014 InstanceFunctionCallback));
9016 // The script to check how Crankshaft compiles missing global function
9017 // invocations. function g is not defined and should throw on call.
9018 const char* script =
9019 "function wrapper(call) {"
9020 " var x = 0, y = 1;"
9021 " for (var i = 0; i < 1000; i++) {"
9027 "for (var i = 0; i < 17; i++) wrapper(false);"
9029 "try { wrapper(true); } catch (e) { thrown = 1; };"
9033 LocalContext env(NULL, instance_template);
9034 // Hold on to the global object so it can be used again in another
9035 // environment initialization.
9036 global_object = env->Global();
9038 Local<Value> value = CompileRun("x");
9039 CHECK_EQ(42, value->Int32Value());
9040 value = CompileRun("f()");
9041 CHECK_EQ(12, value->Int32Value());
9042 value = CompileRun(script);
9043 CHECK_EQ(1, value->Int32Value());
9047 // Create new environment reusing the global object.
9048 LocalContext env(NULL, instance_template, global_object);
9049 Local<Value> value = CompileRun("x");
9050 CHECK_EQ(42, value->Int32Value());
9051 value = CompileRun("f()");
9052 CHECK_EQ(12, value->Int32Value());
9053 value = CompileRun(script);
9054 CHECK_EQ(1, value->Int32Value());
9059 THREADED_TEST(CallKnownGlobalReceiver) {
9060 v8::Isolate* isolate = CcTest::isolate();
9061 v8::HandleScope handle_scope(isolate);
9063 Local<Value> global_object;
9065 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9066 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9068 // The script to check that we leave global object not
9069 // global object proxy on stack when we deoptimize from inside
9070 // arguments evaluation.
9071 // To provoke error we need to both force deoptimization
9072 // from arguments evaluation and to force CallIC to take
9073 // CallIC_Miss code path that can't cope with global proxy.
9074 const char* script =
9075 "function bar(x, y) { try { } finally { } }"
9076 "function baz(x) { try { } finally { } }"
9077 "function bom(x) { try { } finally { } }"
9078 "function foo(x) { bar([x], bom(2)); }"
9079 "for (var i = 0; i < 10000; i++) foo(1);"
9084 LocalContext env(NULL, instance_template);
9085 // Hold on to the global object so it can be used again in another
9086 // environment initialization.
9087 global_object = env->Global();
9088 foo = CompileRun(script);
9092 // Create new environment reusing the global object.
9093 LocalContext env(NULL, instance_template, global_object);
9094 env->Global()->Set(v8_str("foo"), foo);
9095 CompileRun("foo()");
9100 static void ShadowFunctionCallback(
9101 const v8::FunctionCallbackInfo<v8::Value>& args) {
9102 ApiTestFuzzer::Fuzz();
9103 args.GetReturnValue().Set(v8_num(42));
9107 static int shadow_y;
9108 static int shadow_y_setter_call_count;
9109 static int shadow_y_getter_call_count;
9112 static void ShadowYSetter(Local<String>,
9114 const v8::PropertyCallbackInfo<void>&) {
9115 shadow_y_setter_call_count++;
9120 static void ShadowYGetter(Local<String> name,
9121 const v8::PropertyCallbackInfo<v8::Value>& info) {
9122 ApiTestFuzzer::Fuzz();
9123 shadow_y_getter_call_count++;
9124 info.GetReturnValue().Set(v8_num(shadow_y));
9128 static void ShadowIndexedGet(uint32_t index,
9129 const v8::PropertyCallbackInfo<v8::Value>&) {
9133 static void ShadowNamedGet(Local<Name> key,
9134 const v8::PropertyCallbackInfo<v8::Value>&) {}
9137 THREADED_TEST(ShadowObject) {
9138 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
9139 v8::Isolate* isolate = CcTest::isolate();
9140 v8::HandleScope handle_scope(isolate);
9142 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
9143 LocalContext context(NULL, global_template);
9145 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9146 t->InstanceTemplate()->SetHandler(
9147 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
9148 t->InstanceTemplate()->SetHandler(
9149 v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
9150 Local<ObjectTemplate> proto = t->PrototypeTemplate();
9151 Local<ObjectTemplate> instance = t->InstanceTemplate();
9153 proto->Set(v8_str("f"),
9154 v8::FunctionTemplate::New(isolate,
9155 ShadowFunctionCallback,
9157 proto->Set(v8_str("x"), v8_num(12));
9159 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
9161 Local<Value> o = t->GetFunction()->NewInstance();
9162 context->Global()->Set(v8_str("__proto__"), o);
9164 Local<Value> value =
9165 CompileRun("this.propertyIsEnumerable(0)");
9166 CHECK(value->IsBoolean());
9167 CHECK(!value->BooleanValue());
9169 value = CompileRun("x");
9170 CHECK_EQ(12, value->Int32Value());
9172 value = CompileRun("f()");
9173 CHECK_EQ(42, value->Int32Value());
9175 CompileRun("y = 43");
9176 CHECK_EQ(1, shadow_y_setter_call_count);
9177 value = CompileRun("y");
9178 CHECK_EQ(1, shadow_y_getter_call_count);
9179 CHECK_EQ(42, value->Int32Value());
9183 THREADED_TEST(HiddenPrototype) {
9184 LocalContext context;
9185 v8::Isolate* isolate = context->GetIsolate();
9186 v8::HandleScope handle_scope(isolate);
9188 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9189 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9190 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9191 t1->SetHiddenPrototype(true);
9192 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9193 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9194 t2->SetHiddenPrototype(true);
9195 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9196 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9197 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9199 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9200 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9201 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9202 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9204 // Setting the prototype on an object skips hidden prototypes.
9205 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9206 o0->Set(v8_str("__proto__"), o1);
9207 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9208 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9209 o0->Set(v8_str("__proto__"), o2);
9210 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9211 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9212 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9213 o0->Set(v8_str("__proto__"), o3);
9214 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9215 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9216 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9217 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9219 // Getting the prototype of o0 should get the first visible one
9220 // which is o3. Therefore, z should not be defined on the prototype
9222 Local<Value> proto = o0->Get(v8_str("__proto__"));
9223 CHECK(proto->IsObject());
9224 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
9228 THREADED_TEST(HiddenPrototypeSet) {
9229 LocalContext context;
9230 v8::Isolate* isolate = context->GetIsolate();
9231 v8::HandleScope handle_scope(isolate);
9233 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
9234 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
9235 ht->SetHiddenPrototype(true);
9236 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
9237 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9239 Local<v8::Object> o = ot->GetFunction()->NewInstance();
9240 Local<v8::Object> h = ht->GetFunction()->NewInstance();
9241 Local<v8::Object> p = pt->GetFunction()->NewInstance();
9242 o->Set(v8_str("__proto__"), h);
9243 h->Set(v8_str("__proto__"), p);
9245 // Setting a property that exists on the hidden prototype goes there.
9246 o->Set(v8_str("x"), v8_num(7));
9247 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
9248 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
9249 CHECK(p->Get(v8_str("x"))->IsUndefined());
9251 // Setting a new property should not be forwarded to the hidden prototype.
9252 o->Set(v8_str("y"), v8_num(6));
9253 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
9254 CHECK(h->Get(v8_str("y"))->IsUndefined());
9255 CHECK(p->Get(v8_str("y"))->IsUndefined());
9257 // Setting a property that only exists on a prototype of the hidden prototype
9258 // is treated normally again.
9259 p->Set(v8_str("z"), v8_num(8));
9260 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
9261 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9262 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9263 o->Set(v8_str("z"), v8_num(9));
9264 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
9265 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
9266 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
9270 // Regression test for issue 2457.
9271 THREADED_TEST(HiddenPrototypeIdentityHash) {
9272 LocalContext context;
9273 v8::HandleScope handle_scope(context->GetIsolate());
9275 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
9276 t->SetHiddenPrototype(true);
9277 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
9278 Handle<Object> p = t->GetFunction()->NewInstance();
9279 Handle<Object> o = Object::New(context->GetIsolate());
9282 int hash = o->GetIdentityHash();
9284 o->Set(v8_str("foo"), v8_num(42));
9285 DCHECK_EQ(hash, o->GetIdentityHash());
9289 THREADED_TEST(SetPrototype) {
9290 LocalContext context;
9291 v8::Isolate* isolate = context->GetIsolate();
9292 v8::HandleScope handle_scope(isolate);
9294 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
9295 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
9296 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9297 t1->SetHiddenPrototype(true);
9298 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
9299 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9300 t2->SetHiddenPrototype(true);
9301 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
9302 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9303 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
9305 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
9306 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9307 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9308 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9310 // Setting the prototype on an object does not skip hidden prototypes.
9311 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9312 CHECK(o0->SetPrototype(o1));
9313 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9314 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9315 CHECK(o1->SetPrototype(o2));
9316 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9317 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9318 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9319 CHECK(o2->SetPrototype(o3));
9320 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
9321 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
9322 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
9323 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
9325 // Getting the prototype of o0 should get the first visible one
9326 // which is o3. Therefore, z should not be defined on the prototype
9328 Local<Value> proto = o0->Get(v8_str("__proto__"));
9329 CHECK(proto->IsObject());
9330 CHECK(proto.As<v8::Object>()->Equals(o3));
9332 // However, Object::GetPrototype ignores hidden prototype.
9333 Local<Value> proto0 = o0->GetPrototype();
9334 CHECK(proto0->IsObject());
9335 CHECK(proto0.As<v8::Object>()->Equals(o1));
9337 Local<Value> proto1 = o1->GetPrototype();
9338 CHECK(proto1->IsObject());
9339 CHECK(proto1.As<v8::Object>()->Equals(o2));
9341 Local<Value> proto2 = o2->GetPrototype();
9342 CHECK(proto2->IsObject());
9343 CHECK(proto2.As<v8::Object>()->Equals(o3));
9347 // Getting property names of an object with a prototype chain that
9348 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
9349 // crash the runtime.
9350 THREADED_TEST(Regress91517) {
9351 i::FLAG_allow_natives_syntax = true;
9352 LocalContext context;
9353 v8::Isolate* isolate = context->GetIsolate();
9354 v8::HandleScope handle_scope(isolate);
9356 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9357 t1->SetHiddenPrototype(true);
9358 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
9359 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9360 t2->SetHiddenPrototype(true);
9361 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
9362 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
9363 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
9364 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
9365 t3->SetHiddenPrototype(true);
9366 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
9367 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
9368 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
9370 // Force dictionary-based properties.
9371 i::ScopedVector<char> name_buf(1024);
9372 for (int i = 1; i <= 1000; i++) {
9373 i::SNPrintF(name_buf, "sdf%d", i);
9374 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
9377 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9378 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9379 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
9380 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
9382 // Create prototype chain of hidden prototypes.
9383 CHECK(o4->SetPrototype(o3));
9384 CHECK(o3->SetPrototype(o2));
9385 CHECK(o2->SetPrototype(o1));
9387 // Call the runtime version of GetOwnPropertyNames() on the natively
9388 // created object through JavaScript.
9389 context->Global()->Set(v8_str("obj"), o4);
9390 // PROPERTY_ATTRIBUTES_NONE = 0
9391 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
9393 ExpectInt32("names.length", 1006);
9394 ExpectTrue("names.indexOf(\"baz\") >= 0");
9395 ExpectTrue("names.indexOf(\"boo\") >= 0");
9396 ExpectTrue("names.indexOf(\"foo\") >= 0");
9397 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
9398 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
9399 ExpectFalse("names[1005] == undefined");
9403 // Getting property names of an object with a hidden and inherited
9404 // prototype should not duplicate the accessor properties inherited.
9405 THREADED_TEST(Regress269562) {
9406 i::FLAG_allow_natives_syntax = true;
9407 LocalContext context;
9408 v8::HandleScope handle_scope(context->GetIsolate());
9410 Local<v8::FunctionTemplate> t1 =
9411 v8::FunctionTemplate::New(context->GetIsolate());
9412 t1->SetHiddenPrototype(true);
9414 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
9415 i1->SetAccessor(v8_str("foo"),
9416 SimpleAccessorGetter, SimpleAccessorSetter);
9417 i1->SetAccessor(v8_str("bar"),
9418 SimpleAccessorGetter, SimpleAccessorSetter);
9419 i1->SetAccessor(v8_str("baz"),
9420 SimpleAccessorGetter, SimpleAccessorSetter);
9421 i1->Set(v8_str("n1"), v8_num(1));
9422 i1->Set(v8_str("n2"), v8_num(2));
9424 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
9425 Local<v8::FunctionTemplate> t2 =
9426 v8::FunctionTemplate::New(context->GetIsolate());
9427 t2->SetHiddenPrototype(true);
9429 // Inherit from t1 and mark prototype as hidden.
9431 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
9433 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
9434 CHECK(o2->SetPrototype(o1));
9436 v8::Local<v8::Symbol> sym =
9437 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
9438 o1->Set(sym, v8_num(3));
9440 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
9442 // Call the runtime version of GetOwnPropertyNames() on
9443 // the natively created object through JavaScript.
9444 context->Global()->Set(v8_str("obj"), o2);
9445 context->Global()->Set(v8_str("sym"), sym);
9446 // PROPERTY_ATTRIBUTES_NONE = 0
9447 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
9449 ExpectInt32("names.length", 7);
9450 ExpectTrue("names.indexOf(\"foo\") >= 0");
9451 ExpectTrue("names.indexOf(\"bar\") >= 0");
9452 ExpectTrue("names.indexOf(\"baz\") >= 0");
9453 ExpectTrue("names.indexOf(\"n1\") >= 0");
9454 ExpectTrue("names.indexOf(\"n2\") >= 0");
9455 ExpectTrue("names.indexOf(sym) >= 0");
9456 ExpectTrue("names.indexOf(\"mine\") >= 0");
9460 THREADED_TEST(FunctionReadOnlyPrototype) {
9461 LocalContext context;
9462 v8::Isolate* isolate = context->GetIsolate();
9463 v8::HandleScope handle_scope(isolate);
9465 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9466 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9467 t1->ReadOnlyPrototype();
9468 context->Global()->Set(v8_str("func1"), t1->GetFunction());
9469 // Configured value of ReadOnly flag.
9472 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
9473 " return (descriptor['writable'] == false);"
9474 "})()")->BooleanValue());
9475 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
9477 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
9479 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
9480 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9481 context->Global()->Set(v8_str("func2"), t2->GetFunction());
9482 // Default value of ReadOnly flag.
9485 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
9486 " return (descriptor['writable'] == true);"
9487 "})()")->BooleanValue());
9488 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
9492 THREADED_TEST(SetPrototypeThrows) {
9493 LocalContext context;
9494 v8::Isolate* isolate = context->GetIsolate();
9495 v8::HandleScope handle_scope(isolate);
9497 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9499 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
9500 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
9502 CHECK(o0->SetPrototype(o1));
9503 // If setting the prototype leads to the cycle, SetPrototype should
9504 // return false and keep VM in sane state.
9505 v8::TryCatch try_catch;
9506 CHECK(!o1->SetPrototype(o0));
9507 CHECK(!try_catch.HasCaught());
9508 DCHECK(!CcTest::i_isolate()->has_pending_exception());
9510 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
9514 THREADED_TEST(FunctionRemovePrototype) {
9515 LocalContext context;
9516 v8::Isolate* isolate = context->GetIsolate();
9517 v8::HandleScope handle_scope(isolate);
9519 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
9520 t1->RemovePrototype();
9521 Local<v8::Function> fun = t1->GetFunction();
9522 context->Global()->Set(v8_str("fun"), fun);
9523 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
9525 v8::TryCatch try_catch;
9526 CompileRun("new fun()");
9527 CHECK(try_catch.HasCaught());
9531 CHECK(try_catch.HasCaught());
9535 THREADED_TEST(GetterSetterExceptions) {
9536 LocalContext context;
9537 v8::Isolate* isolate = context->GetIsolate();
9538 v8::HandleScope handle_scope(isolate);
9540 "function Foo() { };"
9541 "function Throw() { throw 5; };"
9543 "x.__defineSetter__('set', Throw);"
9544 "x.__defineGetter__('get', Throw);");
9545 Local<v8::Object> x =
9546 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
9547 v8::TryCatch try_catch;
9548 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9549 x->Get(v8_str("get"));
9550 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9551 x->Get(v8_str("get"));
9552 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9553 x->Get(v8_str("get"));
9554 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
9555 x->Get(v8_str("get"));
9559 THREADED_TEST(Constructor) {
9560 LocalContext context;
9561 v8::Isolate* isolate = context->GetIsolate();
9562 v8::HandleScope handle_scope(isolate);
9563 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
9564 templ->SetClassName(v8_str("Fun"));
9565 Local<Function> cons = templ->GetFunction();
9566 context->Global()->Set(v8_str("Fun"), cons);
9567 Local<v8::Object> inst = cons->NewInstance();
9568 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
9569 CHECK(obj->IsJSObject());
9570 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
9571 CHECK(value->BooleanValue());
9575 static void ConstructorCallback(
9576 const v8::FunctionCallbackInfo<v8::Value>& args) {
9577 ApiTestFuzzer::Fuzz();
9580 if (args.IsConstructCall()) {
9581 Local<Object> Holder = args.Holder();
9582 This = Object::New(args.GetIsolate());
9583 Local<Value> proto = Holder->GetPrototype();
9584 if (proto->IsObject()) {
9585 This->SetPrototype(proto);
9591 This->Set(v8_str("a"), args[0]);
9592 args.GetReturnValue().Set(This);
9596 static void FakeConstructorCallback(
9597 const v8::FunctionCallbackInfo<v8::Value>& args) {
9598 ApiTestFuzzer::Fuzz();
9599 args.GetReturnValue().Set(args[0]);
9603 THREADED_TEST(ConstructorForObject) {
9604 LocalContext context;
9605 v8::Isolate* isolate = context->GetIsolate();
9606 v8::HandleScope handle_scope(isolate);
9609 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9610 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
9611 Local<Object> instance = instance_template->NewInstance();
9612 context->Global()->Set(v8_str("obj"), instance);
9613 v8::TryCatch try_catch;
9615 CHECK(!try_catch.HasCaught());
9617 // Call the Object's constructor with a 32-bit signed integer.
9618 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
9619 CHECK(!try_catch.HasCaught());
9620 CHECK(value->IsInt32());
9621 CHECK_EQ(28, value->Int32Value());
9623 Local<Value> args1[] = {v8_num(28)};
9624 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
9625 CHECK(value_obj1->IsObject());
9626 Local<Object> object1 = Local<Object>::Cast(value_obj1);
9627 value = object1->Get(v8_str("a"));
9628 CHECK(value->IsInt32());
9629 CHECK(!try_catch.HasCaught());
9630 CHECK_EQ(28, value->Int32Value());
9632 // Call the Object's constructor with a String.
9634 CompileRun("(function() { var o = new obj('tipli'); return o.a; })()");
9635 CHECK(!try_catch.HasCaught());
9636 CHECK(value->IsString());
9637 String::Utf8Value string_value1(value->ToString(isolate));
9638 CHECK_EQ(0, strcmp("tipli", *string_value1));
9640 Local<Value> args2[] = {v8_str("tipli")};
9641 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
9642 CHECK(value_obj2->IsObject());
9643 Local<Object> object2 = Local<Object>::Cast(value_obj2);
9644 value = object2->Get(v8_str("a"));
9645 CHECK(!try_catch.HasCaught());
9646 CHECK(value->IsString());
9647 String::Utf8Value string_value2(value->ToString(isolate));
9648 CHECK_EQ(0, strcmp("tipli", *string_value2));
9650 // Call the Object's constructor with a Boolean.
9651 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
9652 CHECK(!try_catch.HasCaught());
9653 CHECK(value->IsBoolean());
9654 CHECK_EQ(true, value->BooleanValue());
9656 Handle<Value> args3[] = {v8::True(isolate)};
9657 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
9658 CHECK(value_obj3->IsObject());
9659 Local<Object> object3 = Local<Object>::Cast(value_obj3);
9660 value = object3->Get(v8_str("a"));
9661 CHECK(!try_catch.HasCaught());
9662 CHECK(value->IsBoolean());
9663 CHECK_EQ(true, value->BooleanValue());
9665 // Call the Object's constructor with undefined.
9666 Handle<Value> args4[] = {v8::Undefined(isolate)};
9667 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
9668 CHECK(value_obj4->IsObject());
9669 Local<Object> object4 = Local<Object>::Cast(value_obj4);
9670 value = object4->Get(v8_str("a"));
9671 CHECK(!try_catch.HasCaught());
9672 CHECK(value->IsUndefined());
9674 // Call the Object's constructor with null.
9675 Handle<Value> args5[] = {v8::Null(isolate)};
9676 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
9677 CHECK(value_obj5->IsObject());
9678 Local<Object> object5 = Local<Object>::Cast(value_obj5);
9679 value = object5->Get(v8_str("a"));
9680 CHECK(!try_catch.HasCaught());
9681 CHECK(value->IsNull());
9684 // Check exception handling when there is no constructor set for the Object.
9686 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9687 Local<Object> instance = instance_template->NewInstance();
9688 context->Global()->Set(v8_str("obj2"), instance);
9689 v8::TryCatch try_catch;
9691 CHECK(!try_catch.HasCaught());
9693 value = CompileRun("new obj2(28)");
9694 CHECK(try_catch.HasCaught());
9695 String::Utf8Value exception_value1(try_catch.Exception());
9696 CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
9699 Local<Value> args[] = {v8_num(29)};
9700 value = instance->CallAsConstructor(1, args);
9701 CHECK(try_catch.HasCaught());
9702 String::Utf8Value exception_value2(try_catch.Exception());
9704 0, strcmp("TypeError: #<Object> is not a function", *exception_value2));
9708 // Check the case when constructor throws exception.
9710 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9711 instance_template->SetCallAsFunctionHandler(ThrowValue);
9712 Local<Object> instance = instance_template->NewInstance();
9713 context->Global()->Set(v8_str("obj3"), instance);
9714 v8::TryCatch try_catch;
9716 CHECK(!try_catch.HasCaught());
9718 value = CompileRun("new obj3(22)");
9719 CHECK(try_catch.HasCaught());
9720 String::Utf8Value exception_value1(try_catch.Exception());
9721 CHECK_EQ(0, strcmp("22", *exception_value1));
9724 Local<Value> args[] = {v8_num(23)};
9725 value = instance->CallAsConstructor(1, args);
9726 CHECK(try_catch.HasCaught());
9727 String::Utf8Value exception_value2(try_catch.Exception());
9728 CHECK_EQ(0, strcmp("23", *exception_value2));
9732 // Check whether constructor returns with an object or non-object.
9734 Local<FunctionTemplate> function_template =
9735 FunctionTemplate::New(isolate, FakeConstructorCallback);
9736 Local<Function> function = function_template->GetFunction();
9737 Local<Object> instance1 = function;
9738 context->Global()->Set(v8_str("obj4"), instance1);
9739 v8::TryCatch try_catch;
9741 CHECK(!try_catch.HasCaught());
9743 CHECK(instance1->IsObject());
9744 CHECK(instance1->IsFunction());
9746 value = CompileRun("new obj4(28)");
9747 CHECK(!try_catch.HasCaught());
9748 CHECK(value->IsObject());
9750 Local<Value> args1[] = {v8_num(28)};
9751 value = instance1->CallAsConstructor(1, args1);
9752 CHECK(!try_catch.HasCaught());
9753 CHECK(value->IsObject());
9755 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
9756 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
9757 Local<Object> instance2 = instance_template->NewInstance();
9758 context->Global()->Set(v8_str("obj5"), instance2);
9759 CHECK(!try_catch.HasCaught());
9761 CHECK(instance2->IsObject());
9762 CHECK(!instance2->IsFunction());
9764 value = CompileRun("new obj5(28)");
9765 CHECK(!try_catch.HasCaught());
9766 CHECK(!value->IsObject());
9768 Local<Value> args2[] = {v8_num(28)};
9769 value = instance2->CallAsConstructor(1, args2);
9770 CHECK(!try_catch.HasCaught());
9771 CHECK(!value->IsObject());
9776 THREADED_TEST(FunctionDescriptorException) {
9777 LocalContext context;
9778 v8::Isolate* isolate = context->GetIsolate();
9779 v8::HandleScope handle_scope(isolate);
9780 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
9781 templ->SetClassName(v8_str("Fun"));
9782 Local<Function> cons = templ->GetFunction();
9783 context->Global()->Set(v8_str("Fun"), cons);
9784 Local<Value> value = CompileRun(
9787 " (new Fun()).blah()"
9789 " var str = String(e);"
9790 // " if (str.indexOf('TypeError') == -1) return 1;"
9791 // " if (str.indexOf('[object Fun]') != -1) return 2;"
9792 // " if (str.indexOf('#<Fun>') == -1) return 3;"
9798 CHECK_EQ(0, value->Int32Value());
9802 THREADED_TEST(EvalAliasedDynamic) {
9803 LocalContext current;
9804 v8::HandleScope scope(current->GetIsolate());
9806 // Tests where aliased eval can only be resolved dynamically.
9807 Local<Script> script = v8_compile(
9810 " with (x) { return eval('foo'); }"
9813 "result1 = f(new Object());"
9814 "result2 = f(this);"
9815 "var x = new Object();"
9816 "x.eval = function(x) { return 1; };"
9819 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
9820 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
9821 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
9823 v8::TryCatch try_catch;
9824 script = v8_compile(
9827 " with (x) { return eval('bar'); }"
9829 "result4 = f(this)");
9831 CHECK(!try_catch.HasCaught());
9832 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
9838 THREADED_TEST(CrossEval) {
9839 v8::HandleScope scope(CcTest::isolate());
9841 LocalContext current;
9843 Local<String> token = v8_str("<security token>");
9844 other->SetSecurityToken(token);
9845 current->SetSecurityToken(token);
9847 // Set up reference from current to other.
9848 current->Global()->Set(v8_str("other"), other->Global());
9850 // Check that new variables are introduced in other context.
9851 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
9853 Local<Value> foo = other->Global()->Get(v8_str("foo"));
9854 CHECK_EQ(1234, foo->Int32Value());
9855 CHECK(!current->Global()->Has(v8_str("foo")));
9857 // Check that writing to non-existing properties introduces them in
9858 // the other context.
9859 script = v8_compile("other.eval('na = 1234')");
9861 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
9862 CHECK(!current->Global()->Has(v8_str("na")));
9864 // Check that global variables in current context are not visible in other
9866 v8::TryCatch try_catch;
9867 script = v8_compile("var bar = 42; other.eval('bar');");
9868 Local<Value> result = script->Run();
9869 CHECK(try_catch.HasCaught());
9872 // Check that local variables in current context are not visible in other
9874 script = v8_compile(
9877 " return other.eval('baz');"
9879 result = script->Run();
9880 CHECK(try_catch.HasCaught());
9883 // Check that global variables in the other environment are visible
9884 // when evaluting code.
9885 other->Global()->Set(v8_str("bis"), v8_num(1234));
9886 script = v8_compile("other.eval('bis')");
9887 CHECK_EQ(1234, script->Run()->Int32Value());
9888 CHECK(!try_catch.HasCaught());
9890 // Check that the 'this' pointer points to the global object evaluating
9892 other->Global()->Set(v8_str("t"), other->Global());
9893 script = v8_compile("other.eval('this == t')");
9894 result = script->Run();
9895 CHECK(result->IsTrue());
9896 CHECK(!try_catch.HasCaught());
9898 // Check that variables introduced in with-statement are not visible in
9900 script = v8_compile("with({x:2}){other.eval('x')}");
9901 result = script->Run();
9902 CHECK(try_catch.HasCaught());
9905 // Check that you cannot use 'eval.call' with another object than the
9906 // current global object.
9907 script = v8_compile("other.y = 1; eval.call(other, 'y')");
9908 result = script->Run();
9909 CHECK(try_catch.HasCaught());
9913 // Test that calling eval in a context which has been detached from
9914 // its global proxy works.
9915 THREADED_TEST(EvalInDetachedGlobal) {
9916 v8::Isolate* isolate = CcTest::isolate();
9917 v8::HandleScope scope(isolate);
9919 v8::Local<Context> context0 = Context::New(isolate);
9920 v8::Local<Context> context1 = Context::New(isolate);
9922 // Set up function in context0 that uses eval from context0.
9924 v8::Handle<v8::Value> fun = CompileRun(
9928 " return function(s) { return e(s); }"
9932 // Put the function into context1 and call it before and after
9933 // detaching the global. Before detaching, the call succeeds and
9934 // after detaching and exception is thrown.
9936 context1->Global()->Set(v8_str("fun"), fun);
9937 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
9938 CHECK_EQ(42, x_value->Int32Value());
9939 context0->DetachGlobal();
9940 v8::TryCatch catcher;
9941 x_value = CompileRun("fun('x')");
9942 CHECK_EQ(42, x_value->Int32Value());
9947 THREADED_TEST(CrossLazyLoad) {
9948 v8::HandleScope scope(CcTest::isolate());
9950 LocalContext current;
9952 Local<String> token = v8_str("<security token>");
9953 other->SetSecurityToken(token);
9954 current->SetSecurityToken(token);
9956 // Set up reference from current to other.
9957 current->Global()->Set(v8_str("other"), other->Global());
9959 // Trigger lazy loading in other context.
9960 Local<Script> script = v8_compile("other.eval('new Date(42)')");
9961 Local<Value> value = script->Run();
9962 CHECK_EQ(42.0, value->NumberValue());
9966 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
9967 ApiTestFuzzer::Fuzz();
9968 if (args.IsConstructCall()) {
9969 if (args[0]->IsInt32()) {
9970 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
9975 args.GetReturnValue().Set(args[0]);
9979 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
9980 args.GetReturnValue().Set(args.This());
9984 // Test that a call handler can be set for objects which will allow
9985 // non-function objects created through the API to be called as
9987 THREADED_TEST(CallAsFunction) {
9988 LocalContext context;
9989 v8::Isolate* isolate = context->GetIsolate();
9990 v8::HandleScope scope(isolate);
9993 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
9994 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
9995 instance_template->SetCallAsFunctionHandler(call_as_function);
9996 Local<v8::Object> instance = t->GetFunction()->NewInstance();
9997 context->Global()->Set(v8_str("obj"), instance);
9998 v8::TryCatch try_catch;
10000 CHECK(!try_catch.HasCaught());
10002 value = CompileRun("obj(42)");
10003 CHECK(!try_catch.HasCaught());
10004 CHECK_EQ(42, value->Int32Value());
10006 value = CompileRun("(function(o){return o(49)})(obj)");
10007 CHECK(!try_catch.HasCaught());
10008 CHECK_EQ(49, value->Int32Value());
10010 // test special case of call as function
10011 value = CompileRun("[obj]['0'](45)");
10012 CHECK(!try_catch.HasCaught());
10013 CHECK_EQ(45, value->Int32Value());
10015 value = CompileRun(
10016 "obj.call = Function.prototype.call;"
10017 "obj.call(null, 87)");
10018 CHECK(!try_catch.HasCaught());
10019 CHECK_EQ(87, value->Int32Value());
10021 // Regression tests for bug #1116356: Calling call through call/apply
10022 // must work for non-function receivers.
10023 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
10024 value = CompileRun(apply_99);
10025 CHECK(!try_catch.HasCaught());
10026 CHECK_EQ(99, value->Int32Value());
10028 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
10029 value = CompileRun(call_17);
10030 CHECK(!try_catch.HasCaught());
10031 CHECK_EQ(17, value->Int32Value());
10033 // Check that the call-as-function handler can be called through
10035 value = CompileRun("new obj(43)");
10036 CHECK(!try_catch.HasCaught());
10037 CHECK_EQ(-43, value->Int32Value());
10039 // Check that the call-as-function handler can be called through
10041 v8::Handle<Value> args[] = {v8_num(28)};
10042 value = instance->CallAsFunction(instance, 1, args);
10043 CHECK(!try_catch.HasCaught());
10044 CHECK_EQ(28, value->Int32Value());
10048 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10049 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
10050 USE(instance_template);
10051 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10052 context->Global()->Set(v8_str("obj2"), instance);
10053 v8::TryCatch try_catch;
10054 Local<Value> value;
10055 CHECK(!try_catch.HasCaught());
10057 // Call an object without call-as-function handler through the JS
10058 value = CompileRun("obj2(28)");
10059 CHECK(value.IsEmpty());
10060 CHECK(try_catch.HasCaught());
10061 String::Utf8Value exception_value1(try_catch.Exception());
10062 // TODO(verwaest): Better message
10063 CHECK_EQ(0, strcmp("TypeError: obj2 is not a function", *exception_value1));
10066 // Call an object without call-as-function handler through the API
10067 value = CompileRun("obj2(28)");
10068 v8::Handle<Value> args[] = {v8_num(28)};
10069 value = instance->CallAsFunction(instance, 1, args);
10070 CHECK(value.IsEmpty());
10071 CHECK(try_catch.HasCaught());
10072 String::Utf8Value exception_value2(try_catch.Exception());
10073 CHECK_EQ(0, strcmp("TypeError: [object Object] is not a function",
10074 *exception_value2));
10079 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10080 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10081 instance_template->SetCallAsFunctionHandler(ThrowValue);
10082 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10083 context->Global()->Set(v8_str("obj3"), instance);
10084 v8::TryCatch try_catch;
10085 Local<Value> value;
10086 CHECK(!try_catch.HasCaught());
10088 // Catch the exception which is thrown by call-as-function handler
10089 value = CompileRun("obj3(22)");
10090 CHECK(try_catch.HasCaught());
10091 String::Utf8Value exception_value1(try_catch.Exception());
10092 CHECK_EQ(0, strcmp("22", *exception_value1));
10095 v8::Handle<Value> args[] = {v8_num(23)};
10096 value = instance->CallAsFunction(instance, 1, args);
10097 CHECK(try_catch.HasCaught());
10098 String::Utf8Value exception_value2(try_catch.Exception());
10099 CHECK_EQ(0, strcmp("23", *exception_value2));
10104 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10105 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10106 instance_template->SetCallAsFunctionHandler(ReturnThis);
10107 Local<v8::Object> instance = t->GetFunction()->NewInstance();
10109 Local<v8::Value> a1 =
10110 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10111 CHECK(a1->StrictEquals(instance));
10112 Local<v8::Value> a2 = instance->CallAsFunction(v8::Null(isolate), 0, NULL);
10113 CHECK(a2->StrictEquals(instance));
10114 Local<v8::Value> a3 = instance->CallAsFunction(v8_num(42), 0, NULL);
10115 CHECK(a3->StrictEquals(instance));
10116 Local<v8::Value> a4 = instance->CallAsFunction(v8_str("hello"), 0, NULL);
10117 CHECK(a4->StrictEquals(instance));
10118 Local<v8::Value> a5 = instance->CallAsFunction(v8::True(isolate), 0, NULL);
10119 CHECK(a5->StrictEquals(instance));
10124 "function ReturnThisSloppy() {"
10127 "function ReturnThisStrict() {"
10131 Local<Function> ReturnThisSloppy = Local<Function>::Cast(
10132 context->Global()->Get(v8_str("ReturnThisSloppy")));
10133 Local<Function> ReturnThisStrict = Local<Function>::Cast(
10134 context->Global()->Get(v8_str("ReturnThisStrict")));
10136 Local<v8::Value> a1 =
10137 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10138 CHECK(a1->StrictEquals(context->Global()));
10139 Local<v8::Value> a2 =
10140 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
10141 CHECK(a2->StrictEquals(context->Global()));
10142 Local<v8::Value> a3 = ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
10143 CHECK(a3->IsNumberObject());
10144 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
10145 Local<v8::Value> a4 =
10146 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
10147 CHECK(a4->IsStringObject());
10148 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
10149 Local<v8::Value> a5 =
10150 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
10151 CHECK(a5->IsBooleanObject());
10152 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
10154 Local<v8::Value> a6 =
10155 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
10156 CHECK(a6->IsUndefined());
10157 Local<v8::Value> a7 =
10158 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
10159 CHECK(a7->IsNull());
10160 Local<v8::Value> a8 = ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
10161 CHECK(a8->StrictEquals(v8_num(42)));
10162 Local<v8::Value> a9 =
10163 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
10164 CHECK(a9->StrictEquals(v8_str("hello")));
10165 Local<v8::Value> a10 =
10166 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
10167 CHECK(a10->StrictEquals(v8::True(isolate)));
10172 // Check whether a non-function object is callable.
10173 THREADED_TEST(CallableObject) {
10174 LocalContext context;
10175 v8::Isolate* isolate = context->GetIsolate();
10176 v8::HandleScope scope(isolate);
10179 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10180 instance_template->SetCallAsFunctionHandler(call_as_function);
10181 Local<Object> instance = instance_template->NewInstance();
10182 v8::TryCatch try_catch;
10184 CHECK(instance->IsCallable());
10185 CHECK(!try_catch.HasCaught());
10189 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10190 Local<Object> instance = instance_template->NewInstance();
10191 v8::TryCatch try_catch;
10193 CHECK(!instance->IsCallable());
10194 CHECK(!try_catch.HasCaught());
10198 Local<FunctionTemplate> function_template =
10199 FunctionTemplate::New(isolate, call_as_function);
10200 Local<Function> function = function_template->GetFunction();
10201 Local<Object> instance = function;
10202 v8::TryCatch try_catch;
10204 CHECK(instance->IsCallable());
10205 CHECK(!try_catch.HasCaught());
10209 Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
10210 Local<Function> function = function_template->GetFunction();
10211 Local<Object> instance = function;
10212 v8::TryCatch try_catch;
10214 CHECK(instance->IsCallable());
10215 CHECK(!try_catch.HasCaught());
10220 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
10221 v8::HandleScope scope(isolate);
10222 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
10223 for (int i = 0; i < iterations; i++) {
10224 Local<v8::Number> n(v8::Integer::New(isolate, 42));
10226 return Recurse(isolate, depth - 1, iterations);
10230 THREADED_TEST(HandleIteration) {
10231 static const int kIterations = 500;
10232 static const int kNesting = 200;
10233 LocalContext context;
10234 v8::Isolate* isolate = context->GetIsolate();
10235 v8::HandleScope scope0(isolate);
10236 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10238 v8::HandleScope scope1(isolate);
10239 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10240 for (int i = 0; i < kIterations; i++) {
10241 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
10242 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
10245 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
10247 v8::HandleScope scope2(CcTest::isolate());
10248 for (int j = 0; j < kIterations; j++) {
10249 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
10250 CHECK_EQ(j + 1 + kIterations,
10251 v8::HandleScope::NumberOfHandles(isolate));
10254 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
10256 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
10257 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
10261 static void InterceptorCallICFastApi(
10262 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
10263 ApiTestFuzzer::Fuzz();
10264 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
10266 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
10268 if ((*call_count) % 20 == 0) {
10269 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
10273 static void FastApiCallback_TrivialSignature(
10274 const v8::FunctionCallbackInfo<v8::Value>& args) {
10275 ApiTestFuzzer::Fuzz();
10276 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
10277 v8::Isolate* isolate = CcTest::isolate();
10278 CHECK_EQ(isolate, args.GetIsolate());
10279 CHECK(args.This()->Equals(args.Holder()));
10280 CHECK(args.Data()->Equals(v8_str("method_data")));
10281 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10284 static void FastApiCallback_SimpleSignature(
10285 const v8::FunctionCallbackInfo<v8::Value>& args) {
10286 ApiTestFuzzer::Fuzz();
10287 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
10288 v8::Isolate* isolate = CcTest::isolate();
10289 CHECK_EQ(isolate, args.GetIsolate());
10290 CHECK(args.This()->GetPrototype()->Equals(args.Holder()));
10291 CHECK(args.Data()->Equals(v8_str("method_data")));
10292 // Note, we're using HasRealNamedProperty instead of Has to avoid
10293 // invoking the interceptor again.
10294 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
10295 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
10299 // Helper to maximize the odds of object moving.
10300 static void GenerateSomeGarbage() {
10303 "for (var i = 0; i < 1000; i++) {"
10304 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
10306 "garbage = undefined;");
10310 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
10311 static int count = 0;
10312 if (count++ % 3 == 0) {
10313 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
10314 // This should move the stub
10315 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
10320 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
10321 LocalContext context;
10322 v8::Isolate* isolate = context->GetIsolate();
10323 v8::HandleScope scope(isolate);
10324 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
10325 v8::ObjectTemplate::New(isolate);
10326 nativeobject_templ->Set(isolate, "callback",
10327 v8::FunctionTemplate::New(isolate,
10328 DirectApiCallback));
10329 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10330 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10331 // call the api function multiple times to ensure direct call stub creation.
10334 " for (var i = 1; i <= 30; i++) {"
10335 " nativeobject.callback();"
10342 void ThrowingDirectApiCallback(
10343 const v8::FunctionCallbackInfo<v8::Value>& args) {
10344 args.GetIsolate()->ThrowException(v8_str("g"));
10348 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
10349 LocalContext context;
10350 v8::Isolate* isolate = context->GetIsolate();
10351 v8::HandleScope scope(isolate);
10352 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
10353 v8::ObjectTemplate::New(isolate);
10354 nativeobject_templ->Set(isolate, "callback",
10355 v8::FunctionTemplate::New(isolate,
10356 ThrowingDirectApiCallback));
10357 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
10358 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
10359 // call the api function multiple times to ensure direct call stub creation.
10360 v8::Handle<Value> result = CompileRun(
10363 " for (var i = 1; i <= 5; i++) {"
10364 " try { nativeobject.callback(); } catch (e) { result += e; }"
10368 CHECK(v8_str("ggggg")->Equals(result));
10372 static int p_getter_count_3;
10375 static Handle<Value> DoDirectGetter() {
10376 if (++p_getter_count_3 % 3 == 0) {
10377 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
10378 GenerateSomeGarbage();
10380 return v8_str("Direct Getter Result");
10384 static void DirectGetterCallback(
10385 Local<String> name,
10386 const v8::PropertyCallbackInfo<v8::Value>& info) {
10387 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
10388 info.GetReturnValue().Set(DoDirectGetter());
10392 template<typename Accessor>
10393 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
10394 LocalContext context;
10395 v8::Isolate* isolate = context->GetIsolate();
10396 v8::HandleScope scope(isolate);
10397 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
10398 obj->SetAccessor(v8_str("p1"), accessor);
10399 context->Global()->Set(v8_str("o1"), obj->NewInstance());
10400 p_getter_count_3 = 0;
10401 v8::Handle<v8::Value> result = CompileRun(
10403 " for (var i = 0; i < 30; i++) o1.p1;"
10407 CHECK(v8_str("Direct Getter Result")->Equals(result));
10408 CHECK_EQ(31, p_getter_count_3);
10412 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
10413 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
10417 void ThrowingDirectGetterCallback(
10418 Local<String> name,
10419 const v8::PropertyCallbackInfo<v8::Value>& info) {
10420 info.GetIsolate()->ThrowException(v8_str("g"));
10424 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
10425 LocalContext context;
10426 v8::Isolate* isolate = context->GetIsolate();
10427 v8::HandleScope scope(isolate);
10428 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
10429 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
10430 context->Global()->Set(v8_str("o1"), obj->NewInstance());
10431 v8::Handle<Value> result = CompileRun(
10433 "for (var i = 0; i < 5; i++) {"
10434 " try { o1.p1; } catch (e) { result += e; }"
10437 CHECK(v8_str("ggggg")->Equals(result));
10441 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
10442 int interceptor_call_count = 0;
10443 v8::Isolate* isolate = CcTest::isolate();
10444 v8::HandleScope scope(isolate);
10445 v8::Handle<v8::FunctionTemplate> fun_templ =
10446 v8::FunctionTemplate::New(isolate);
10447 v8::Handle<v8::FunctionTemplate> method_templ =
10448 v8::FunctionTemplate::New(isolate,
10449 FastApiCallback_TrivialSignature,
10450 v8_str("method_data"),
10451 v8::Handle<v8::Signature>());
10452 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10453 proto_templ->Set(v8_str("method"), method_templ);
10454 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10455 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10456 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10457 v8::External::New(isolate, &interceptor_call_count)));
10458 LocalContext context;
10459 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10460 GenerateSomeGarbage();
10461 context->Global()->Set(v8_str("o"), fun->NewInstance());
10464 "for (var i = 0; i < 100; i++) {"
10465 " result = o.method(41);"
10467 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10468 CHECK_EQ(100, interceptor_call_count);
10472 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
10473 int interceptor_call_count = 0;
10474 v8::Isolate* isolate = CcTest::isolate();
10475 v8::HandleScope scope(isolate);
10476 v8::Handle<v8::FunctionTemplate> fun_templ =
10477 v8::FunctionTemplate::New(isolate);
10478 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10479 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10480 v8::Signature::New(isolate, fun_templ));
10481 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10482 proto_templ->Set(v8_str("method"), method_templ);
10483 fun_templ->SetHiddenPrototype(true);
10484 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10485 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10486 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10487 v8::External::New(isolate, &interceptor_call_count)));
10488 LocalContext context;
10489 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10490 GenerateSomeGarbage();
10491 context->Global()->Set(v8_str("o"), fun->NewInstance());
10494 "var receiver = {};"
10495 "receiver.__proto__ = o;"
10497 "for (var i = 0; i < 100; i++) {"
10498 " result = receiver.method(41);"
10500 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10501 CHECK_EQ(100, interceptor_call_count);
10505 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
10506 int interceptor_call_count = 0;
10507 v8::Isolate* isolate = CcTest::isolate();
10508 v8::HandleScope scope(isolate);
10509 v8::Handle<v8::FunctionTemplate> fun_templ =
10510 v8::FunctionTemplate::New(isolate);
10511 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10512 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10513 v8::Signature::New(isolate, fun_templ));
10514 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10515 proto_templ->Set(v8_str("method"), method_templ);
10516 fun_templ->SetHiddenPrototype(true);
10517 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10518 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10519 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10520 v8::External::New(isolate, &interceptor_call_count)));
10521 LocalContext context;
10522 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10523 GenerateSomeGarbage();
10524 context->Global()->Set(v8_str("o"), fun->NewInstance());
10527 "var receiver = {};"
10528 "receiver.__proto__ = o;"
10530 "var saved_result = 0;"
10531 "for (var i = 0; i < 100; i++) {"
10532 " result = receiver.method(41);"
10534 " saved_result = result;"
10535 " receiver = {method: function(x) { return x - 1 }};"
10538 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10539 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10540 CHECK_GE(interceptor_call_count, 50);
10544 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
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 = v8::FunctionTemplate::New(
10551 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10552 v8::Signature::New(isolate, fun_templ));
10553 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10554 proto_templ->Set(v8_str("method"), method_templ);
10555 fun_templ->SetHiddenPrototype(true);
10556 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10557 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10558 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10559 v8::External::New(isolate, &interceptor_call_count)));
10560 LocalContext context;
10561 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10562 GenerateSomeGarbage();
10563 context->Global()->Set(v8_str("o"), fun->NewInstance());
10566 "var receiver = {};"
10567 "receiver.__proto__ = o;"
10569 "var saved_result = 0;"
10570 "for (var i = 0; i < 100; i++) {"
10571 " result = receiver.method(41);"
10573 " saved_result = result;"
10574 " o.method = function(x) { return x - 1 };"
10577 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10578 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10579 CHECK_GE(interceptor_call_count, 50);
10583 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
10584 int interceptor_call_count = 0;
10585 v8::Isolate* isolate = CcTest::isolate();
10586 v8::HandleScope scope(isolate);
10587 v8::Handle<v8::FunctionTemplate> fun_templ =
10588 v8::FunctionTemplate::New(isolate);
10589 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10590 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10591 v8::Signature::New(isolate, fun_templ));
10592 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10593 proto_templ->Set(v8_str("method"), method_templ);
10594 fun_templ->SetHiddenPrototype(true);
10595 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10596 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10597 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10598 v8::External::New(isolate, &interceptor_call_count)));
10599 LocalContext context;
10600 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10601 GenerateSomeGarbage();
10602 context->Global()->Set(v8_str("o"), fun->NewInstance());
10603 v8::TryCatch try_catch;
10606 "var receiver = {};"
10607 "receiver.__proto__ = o;"
10609 "var saved_result = 0;"
10610 "for (var i = 0; i < 100; i++) {"
10611 " result = receiver.method(41);"
10613 " saved_result = result;"
10617 CHECK(try_catch.HasCaught());
10618 // TODO(verwaest): Adjust message.
10619 CHECK(v8_str("TypeError: receiver.method is not a function")
10620 ->Equals(try_catch.Exception()->ToString(isolate)));
10621 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10622 CHECK_GE(interceptor_call_count, 50);
10626 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
10627 int interceptor_call_count = 0;
10628 v8::Isolate* isolate = CcTest::isolate();
10629 v8::HandleScope scope(isolate);
10630 v8::Handle<v8::FunctionTemplate> fun_templ =
10631 v8::FunctionTemplate::New(isolate);
10632 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10633 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10634 v8::Signature::New(isolate, fun_templ));
10635 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10636 proto_templ->Set(v8_str("method"), method_templ);
10637 fun_templ->SetHiddenPrototype(true);
10638 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
10639 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
10640 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
10641 v8::External::New(isolate, &interceptor_call_count)));
10642 LocalContext context;
10643 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10644 GenerateSomeGarbage();
10645 context->Global()->Set(v8_str("o"), fun->NewInstance());
10646 v8::TryCatch try_catch;
10649 "var receiver = {};"
10650 "receiver.__proto__ = o;"
10652 "var saved_result = 0;"
10653 "for (var i = 0; i < 100; i++) {"
10654 " result = receiver.method(41);"
10656 " saved_result = result;"
10657 " receiver = {method: receiver.method};"
10660 CHECK(try_catch.HasCaught());
10661 CHECK(v8_str("TypeError: Illegal invocation")
10662 ->Equals(try_catch.Exception()->ToString(isolate)));
10663 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10664 CHECK_GE(interceptor_call_count, 50);
10668 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
10669 v8::Isolate* isolate = CcTest::isolate();
10670 v8::HandleScope scope(isolate);
10671 v8::Handle<v8::FunctionTemplate> fun_templ =
10672 v8::FunctionTemplate::New(isolate);
10673 v8::Handle<v8::FunctionTemplate> method_templ =
10674 v8::FunctionTemplate::New(isolate,
10675 FastApiCallback_TrivialSignature,
10676 v8_str("method_data"),
10677 v8::Handle<v8::Signature>());
10678 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10679 proto_templ->Set(v8_str("method"), method_templ);
10680 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10682 LocalContext context;
10683 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10684 GenerateSomeGarbage();
10685 context->Global()->Set(v8_str("o"), fun->NewInstance());
10688 "for (var i = 0; i < 100; i++) {"
10689 " result = o.method(41);"
10692 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10696 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
10697 v8::Isolate* isolate = CcTest::isolate();
10698 v8::HandleScope scope(isolate);
10699 v8::Handle<v8::FunctionTemplate> fun_templ =
10700 v8::FunctionTemplate::New(isolate);
10701 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10702 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10703 v8::Signature::New(isolate, fun_templ));
10704 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10705 proto_templ->Set(v8_str("method"), method_templ);
10706 fun_templ->SetHiddenPrototype(true);
10707 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10708 CHECK(!templ.IsEmpty());
10709 LocalContext context;
10710 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10711 GenerateSomeGarbage();
10712 context->Global()->Set(v8_str("o"), fun->NewInstance());
10715 "var receiver = {};"
10716 "receiver.__proto__ = o;"
10718 "for (var i = 0; i < 100; i++) {"
10719 " result = receiver.method(41);"
10722 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
10726 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
10727 v8::Isolate* isolate = CcTest::isolate();
10728 v8::HandleScope scope(isolate);
10729 v8::Handle<v8::FunctionTemplate> fun_templ =
10730 v8::FunctionTemplate::New(isolate);
10731 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10732 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10733 v8::Signature::New(isolate, fun_templ));
10734 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10735 proto_templ->Set(v8_str("method"), method_templ);
10736 fun_templ->SetHiddenPrototype(true);
10737 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10738 CHECK(!templ.IsEmpty());
10739 LocalContext context;
10740 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10741 GenerateSomeGarbage();
10742 context->Global()->Set(v8_str("o"), fun->NewInstance());
10745 "var receiver = {};"
10746 "receiver.__proto__ = o;"
10748 "var saved_result = 0;"
10749 "for (var i = 0; i < 100; i++) {"
10750 " result = receiver.method(41);"
10752 " saved_result = result;"
10753 " receiver = {method: function(x) { return x - 1 }};"
10756 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
10757 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10761 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
10762 v8::Isolate* isolate = CcTest::isolate();
10763 v8::HandleScope scope(isolate);
10764 v8::Handle<v8::FunctionTemplate> fun_templ =
10765 v8::FunctionTemplate::New(isolate);
10766 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10767 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10768 v8::Signature::New(isolate, fun_templ));
10769 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10770 proto_templ->Set(v8_str("method"), method_templ);
10771 fun_templ->SetHiddenPrototype(true);
10772 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10773 CHECK(!templ.IsEmpty());
10774 LocalContext context;
10775 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10776 GenerateSomeGarbage();
10777 context->Global()->Set(v8_str("o"), fun->NewInstance());
10778 v8::TryCatch try_catch;
10781 "var receiver = {};"
10782 "receiver.__proto__ = o;"
10784 "var saved_result = 0;"
10785 "for (var i = 0; i < 100; i++) {"
10786 " result = receiver.method(41);"
10788 " saved_result = result;"
10792 CHECK(try_catch.HasCaught());
10793 // TODO(verwaest): Adjust message.
10794 CHECK(v8_str("TypeError: receiver.method is not a function")
10795 ->Equals(try_catch.Exception()->ToString(isolate)));
10796 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10800 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
10801 v8::Isolate* isolate = CcTest::isolate();
10802 v8::HandleScope scope(isolate);
10803 v8::Handle<v8::FunctionTemplate> fun_templ =
10804 v8::FunctionTemplate::New(isolate);
10805 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
10806 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
10807 v8::Signature::New(isolate, fun_templ));
10808 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
10809 proto_templ->Set(v8_str("method"), method_templ);
10810 fun_templ->SetHiddenPrototype(true);
10811 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
10812 CHECK(!templ.IsEmpty());
10813 LocalContext context;
10814 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
10815 GenerateSomeGarbage();
10816 context->Global()->Set(v8_str("o"), fun->NewInstance());
10817 v8::TryCatch try_catch;
10820 "var receiver = {};"
10821 "receiver.__proto__ = o;"
10823 "var saved_result = 0;"
10824 "for (var i = 0; i < 100; i++) {"
10825 " result = receiver.method(41);"
10827 " saved_result = result;"
10828 " receiver = Object.create(receiver);"
10831 CHECK(try_catch.HasCaught());
10832 CHECK(v8_str("TypeError: Illegal invocation")
10833 ->Equals(try_catch.Exception()->ToString(isolate)));
10834 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
10838 static void ThrowingGetter(Local<String> name,
10839 const v8::PropertyCallbackInfo<v8::Value>& info) {
10840 ApiTestFuzzer::Fuzz();
10841 info.GetIsolate()->ThrowException(Handle<Value>());
10842 info.GetReturnValue().SetUndefined();
10846 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
10847 LocalContext context;
10848 HandleScope scope(context->GetIsolate());
10850 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
10851 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
10852 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
10854 Local<Object> instance = templ->GetFunction()->NewInstance();
10856 Local<Object> another = Object::New(context->GetIsolate());
10857 another->SetPrototype(instance);
10859 Local<Object> with_js_getter = CompileRun(
10861 "o.__defineGetter__('f', function() { throw undefined; });\n"
10862 "o\n").As<Object>();
10863 CHECK(!with_js_getter.IsEmpty());
10865 TryCatch try_catch;
10867 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
10868 CHECK(try_catch.HasCaught());
10870 CHECK(result.IsEmpty());
10872 result = another->GetRealNamedProperty(v8_str("f"));
10873 CHECK(try_catch.HasCaught());
10875 CHECK(result.IsEmpty());
10877 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
10878 CHECK(try_catch.HasCaught());
10880 CHECK(result.IsEmpty());
10882 result = another->Get(v8_str("f"));
10883 CHECK(try_catch.HasCaught());
10885 CHECK(result.IsEmpty());
10887 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
10888 CHECK(try_catch.HasCaught());
10890 CHECK(result.IsEmpty());
10892 result = with_js_getter->Get(v8_str("f"));
10893 CHECK(try_catch.HasCaught());
10895 CHECK(result.IsEmpty());
10899 static void ThrowingCallbackWithTryCatch(
10900 const v8::FunctionCallbackInfo<v8::Value>& args) {
10901 TryCatch try_catch;
10902 // Verboseness is important: it triggers message delivery which can call into
10904 try_catch.SetVerbose(true);
10905 CompileRun("throw 'from JS';");
10906 CHECK(try_catch.HasCaught());
10907 CHECK(!CcTest::i_isolate()->has_pending_exception());
10908 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
10912 static int call_depth;
10915 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
10916 TryCatch try_catch;
10920 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
10921 if (--call_depth) CompileRun("throw 'ThrowInJS';");
10925 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
10926 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
10930 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
10931 Handle<String> errorMessageString = message->Get();
10932 CHECK(!errorMessageString.IsEmpty());
10933 message->GetStackTrace();
10934 message->GetScriptOrigin().ResourceName();
10938 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
10939 LocalContext context;
10940 v8::Isolate* isolate = context->GetIsolate();
10941 HandleScope scope(isolate);
10943 Local<Function> func =
10944 FunctionTemplate::New(isolate,
10945 ThrowingCallbackWithTryCatch)->GetFunction();
10946 context->Global()->Set(v8_str("func"), func);
10948 MessageCallback callbacks[] =
10949 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
10950 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
10951 MessageCallback callback = callbacks[i];
10952 if (callback != NULL) {
10953 V8::AddMessageListener(callback);
10955 // Some small number to control number of times message handler should
10956 // throw an exception.
10959 "var thrown = false;\n"
10960 "try { func(); } catch(e) { thrown = true; }\n"
10962 if (callback != NULL) {
10963 V8::RemoveMessageListeners(callback);
10969 static void ParentGetter(Local<String> name,
10970 const v8::PropertyCallbackInfo<v8::Value>& info) {
10971 ApiTestFuzzer::Fuzz();
10972 info.GetReturnValue().Set(v8_num(1));
10976 static void ChildGetter(Local<String> name,
10977 const v8::PropertyCallbackInfo<v8::Value>& info) {
10978 ApiTestFuzzer::Fuzz();
10979 info.GetReturnValue().Set(v8_num(42));
10983 THREADED_TEST(Overriding) {
10984 LocalContext context;
10985 v8::Isolate* isolate = context->GetIsolate();
10986 v8::HandleScope scope(isolate);
10988 // Parent template.
10989 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
10990 Local<ObjectTemplate> parent_instance_templ =
10991 parent_templ->InstanceTemplate();
10992 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
10994 // Template that inherits from the parent template.
10995 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
10996 Local<ObjectTemplate> child_instance_templ =
10997 child_templ->InstanceTemplate();
10998 child_templ->Inherit(parent_templ);
10999 // Override 'f'. The child version of 'f' should get called for child
11001 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
11002 // Add 'g' twice. The 'g' added last should get called for instances.
11003 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
11004 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
11006 // Add 'h' as an accessor to the proto template with ReadOnly attributes
11007 // so 'h' can be shadowed on the instance object.
11008 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
11009 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
11010 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11012 // Add 'i' as an accessor to the instance template with ReadOnly attributes
11013 // but the attribute does not have effect because it is duplicated with
11015 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
11016 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
11020 // Instantiate the child template.
11021 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
11023 // Check that the child function overrides the parent one.
11024 context->Global()->Set(v8_str("o"), instance);
11025 Local<Value> value = v8_compile("o.f")->Run();
11026 // Check that the 'g' that was added last is hit.
11027 CHECK_EQ(42, value->Int32Value());
11028 value = v8_compile("o.g")->Run();
11029 CHECK_EQ(42, value->Int32Value());
11031 // Check that 'h' cannot be shadowed.
11032 value = v8_compile("o.h = 3; o.h")->Run();
11033 CHECK_EQ(1, value->Int32Value());
11035 // Check that 'i' cannot be shadowed or changed.
11036 value = v8_compile("o.i = 3; o.i")->Run();
11037 CHECK_EQ(42, value->Int32Value());
11041 static void IsConstructHandler(
11042 const v8::FunctionCallbackInfo<v8::Value>& args) {
11043 ApiTestFuzzer::Fuzz();
11044 args.GetReturnValue().Set(args.IsConstructCall());
11048 THREADED_TEST(IsConstructCall) {
11049 v8::Isolate* isolate = CcTest::isolate();
11050 v8::HandleScope scope(isolate);
11052 // Function template with call handler.
11053 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11054 templ->SetCallHandler(IsConstructHandler);
11056 LocalContext context;
11058 context->Global()->Set(v8_str("f"), templ->GetFunction());
11059 Local<Value> value = v8_compile("f()")->Run();
11060 CHECK(!value->BooleanValue());
11061 value = v8_compile("new f()")->Run();
11062 CHECK(value->BooleanValue());
11066 THREADED_TEST(ObjectProtoToString) {
11067 v8::Isolate* isolate = CcTest::isolate();
11068 v8::HandleScope scope(isolate);
11069 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11070 templ->SetClassName(v8_str("MyClass"));
11072 LocalContext context;
11074 Local<String> customized_tostring = v8_str("customized toString");
11076 // Replace Object.prototype.toString
11077 v8_compile("Object.prototype.toString = function() {"
11078 " return 'customized toString';"
11081 // Normal ToString call should call replaced Object.prototype.toString
11082 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11083 Local<String> value = instance->ToString(isolate);
11084 CHECK(value->IsString() && value->Equals(customized_tostring));
11086 // ObjectProtoToString should not call replace toString function.
11087 value = instance->ObjectProtoToString();
11088 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11091 value = context->Global()->ObjectProtoToString();
11092 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11094 // Check ordinary object
11095 Local<Value> object = v8_compile("new Object()")->Run();
11096 value = object.As<v8::Object>()->ObjectProtoToString();
11097 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11101 TEST(ObjectProtoToStringES6) {
11102 // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
11103 i::FLAG_harmony_tostring = true;
11104 LocalContext context;
11105 v8::Isolate* isolate = CcTest::isolate();
11106 v8::HandleScope scope(isolate);
11107 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11108 templ->SetClassName(v8_str("MyClass"));
11110 Local<String> customized_tostring = v8_str("customized toString");
11112 // Replace Object.prototype.toString
11114 "Object.prototype.toString = function() {"
11115 " return 'customized toString';"
11118 // Normal ToString call should call replaced Object.prototype.toString
11119 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
11120 Local<String> value = instance->ToString(isolate);
11121 CHECK(value->IsString() && value->Equals(customized_tostring));
11123 // ObjectProtoToString should not call replace toString function.
11124 value = instance->ObjectProtoToString();
11125 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
11128 value = context->Global()->ObjectProtoToString();
11129 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
11131 // Check ordinary object
11132 Local<Value> object = CompileRun("new Object()");
11133 value = object.As<v8::Object>()->ObjectProtoToString();
11134 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
11136 // Check that ES6 semantics using @@toStringTag work
11137 Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
11139 #define TEST_TOSTRINGTAG(type, tag, expected) \
11141 object = CompileRun("new " #type "()"); \
11142 object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
11143 value = object.As<v8::Object>()->ObjectProtoToString(); \
11144 CHECK(value->IsString() && \
11145 value->Equals(v8_str("[object " #expected "]"))); \
11148 TEST_TOSTRINGTAG(Array, Object, Object);
11149 TEST_TOSTRINGTAG(Object, Arguments, Arguments);
11150 TEST_TOSTRINGTAG(Object, Array, Array);
11151 TEST_TOSTRINGTAG(Object, Boolean, Boolean);
11152 TEST_TOSTRINGTAG(Object, Date, Date);
11153 TEST_TOSTRINGTAG(Object, Error, Error);
11154 TEST_TOSTRINGTAG(Object, Function, Function);
11155 TEST_TOSTRINGTAG(Object, Number, Number);
11156 TEST_TOSTRINGTAG(Object, RegExp, RegExp);
11157 TEST_TOSTRINGTAG(Object, String, String);
11158 TEST_TOSTRINGTAG(Object, Foo, Foo);
11160 #undef TEST_TOSTRINGTAG
11162 Local<v8::RegExp> valueRegExp = v8::RegExp::New(v8_str("^$"),
11163 v8::RegExp::kNone);
11164 Local<Value> valueNumber = v8_num(123);
11165 Local<v8::Symbol> valueSymbol = v8_symbol("TestSymbol");
11166 Local<v8::Function> valueFunction =
11167 CompileRun("(function fn() {})").As<v8::Function>();
11168 Local<v8::Object> valueObject = v8::Object::New(v8::Isolate::GetCurrent());
11169 Local<v8::Primitive> valueNull = v8::Null(v8::Isolate::GetCurrent());
11170 Local<v8::Primitive> valueUndef = v8::Undefined(v8::Isolate::GetCurrent());
11172 #define TEST_TOSTRINGTAG(type, tagValue, expected) \
11174 object = CompileRun("new " #type "()"); \
11175 object.As<v8::Object>()->Set(toStringTag, tagValue); \
11176 value = object.As<v8::Object>()->ObjectProtoToString(); \
11177 CHECK(value->IsString() && \
11178 value->Equals(v8_str("[object " #expected "]"))); \
11181 #define TEST_TOSTRINGTAG_TYPES(tagValue) \
11182 TEST_TOSTRINGTAG(Array, tagValue, Array); \
11183 TEST_TOSTRINGTAG(Object, tagValue, Object); \
11184 TEST_TOSTRINGTAG(Function, tagValue, Function); \
11185 TEST_TOSTRINGTAG(Date, tagValue, Date); \
11186 TEST_TOSTRINGTAG(RegExp, tagValue, RegExp); \
11187 TEST_TOSTRINGTAG(Error, tagValue, Error); \
11189 // Test non-String-valued @@toStringTag
11190 TEST_TOSTRINGTAG_TYPES(valueRegExp);
11191 TEST_TOSTRINGTAG_TYPES(valueNumber);
11192 TEST_TOSTRINGTAG_TYPES(valueSymbol);
11193 TEST_TOSTRINGTAG_TYPES(valueFunction);
11194 TEST_TOSTRINGTAG_TYPES(valueObject);
11195 TEST_TOSTRINGTAG_TYPES(valueNull);
11196 TEST_TOSTRINGTAG_TYPES(valueUndef);
11198 #undef TEST_TOSTRINGTAG
11199 #undef TEST_TOSTRINGTAG_TYPES
11201 // @@toStringTag getter throws
11202 Local<Value> obj = v8::Object::New(isolate);
11203 obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
11205 TryCatch try_catch;
11206 value = obj.As<v8::Object>()->ObjectProtoToString();
11207 CHECK(value.IsEmpty());
11208 CHECK(try_catch.HasCaught());
11211 // @@toStringTag getter does not throw
11212 obj = v8::Object::New(isolate);
11213 obj.As<v8::Object>()->SetAccessor(
11214 toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
11216 TryCatch try_catch;
11217 value = obj.As<v8::Object>()->ObjectProtoToString();
11218 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11219 CHECK(!try_catch.HasCaught());
11222 // JS @@toStringTag value
11223 obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
11225 TryCatch try_catch;
11226 value = obj.As<v8::Object>()->ObjectProtoToString();
11227 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11228 CHECK(!try_catch.HasCaught());
11231 // JS @@toStringTag getter throws
11233 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
11234 " get: function() { throw 'Test'; }"
11237 TryCatch try_catch;
11238 value = obj.As<v8::Object>()->ObjectProtoToString();
11239 CHECK(value.IsEmpty());
11240 CHECK(try_catch.HasCaught());
11243 // JS @@toStringTag getter does not throw
11245 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
11246 " get: function() { return 'Test'; }"
11249 TryCatch try_catch;
11250 value = obj.As<v8::Object>()->ObjectProtoToString();
11251 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
11252 CHECK(!try_catch.HasCaught());
11257 THREADED_TEST(ObjectGetConstructorName) {
11258 v8::Isolate* isolate = CcTest::isolate();
11259 LocalContext context;
11260 v8::HandleScope scope(isolate);
11261 v8_compile("function Parent() {};"
11262 "function Child() {};"
11263 "Child.prototype = new Parent();"
11264 "var outer = { inner: function() { } };"
11265 "var p = new Parent();"
11266 "var c = new Child();"
11267 "var x = new outer.inner();")->Run();
11269 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
11270 CHECK(p->IsObject() &&
11271 p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
11273 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
11274 CHECK(c->IsObject() &&
11275 c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
11277 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
11278 CHECK(x->IsObject() &&
11279 x->ToObject(isolate)->GetConstructorName()->Equals(
11280 v8_str("outer.inner")));
11284 bool ApiTestFuzzer::fuzzing_ = false;
11285 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
11286 int ApiTestFuzzer::active_tests_;
11287 int ApiTestFuzzer::tests_being_run_;
11288 int ApiTestFuzzer::current_;
11291 // We are in a callback and want to switch to another thread (if we
11292 // are currently running the thread fuzzing test).
11293 void ApiTestFuzzer::Fuzz() {
11294 if (!fuzzing_) return;
11295 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
11296 test->ContextSwitch();
11300 // Let the next thread go. Since it is also waiting on the V8 lock it may
11301 // not start immediately.
11302 bool ApiTestFuzzer::NextThread() {
11303 int test_position = GetNextTestNumber();
11304 const char* test_name = RegisterThreadedTest::nth(current_)->name();
11305 if (test_position == current_) {
11307 printf("Stay with %s\n", test_name);
11310 if (kLogThreading) {
11311 printf("Switch from %s to %s\n",
11313 RegisterThreadedTest::nth(test_position)->name());
11315 current_ = test_position;
11316 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
11321 void ApiTestFuzzer::Run() {
11322 // When it is our turn...
11325 // ... get the V8 lock and start running the test.
11326 v8::Locker locker(CcTest::isolate());
11329 // This test finished.
11332 // If it was the last then signal that fact.
11333 if (active_tests_ == 0) {
11334 all_tests_done_.Signal();
11336 // Otherwise select a new test and start that.
11342 static unsigned linear_congruential_generator;
11345 void ApiTestFuzzer::SetUp(PartOfTest part) {
11346 linear_congruential_generator = i::FLAG_testing_prng_seed;
11348 int count = RegisterThreadedTest::count();
11349 int start = count * part / (LAST_PART + 1);
11350 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
11351 active_tests_ = tests_being_run_ = end - start + 1;
11352 for (int i = 0; i < tests_being_run_; i++) {
11353 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
11355 for (int i = 0; i < active_tests_; i++) {
11356 RegisterThreadedTest::nth(i)->fuzzer_->Start();
11361 static void CallTestNumber(int test_number) {
11362 (RegisterThreadedTest::nth(test_number)->callback())();
11366 void ApiTestFuzzer::RunAllTests() {
11367 // Set off the first test.
11370 // Wait till they are all done.
11371 all_tests_done_.Wait();
11375 int ApiTestFuzzer::GetNextTestNumber() {
11378 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
11379 linear_congruential_generator *= 1664525u;
11380 linear_congruential_generator += 1013904223u;
11381 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
11386 void ApiTestFuzzer::ContextSwitch() {
11387 // If the new thread is the same as the current thread there is nothing to do.
11388 if (NextThread()) {
11389 // Now it can start.
11390 v8::Unlocker unlocker(CcTest::isolate());
11391 // Wait till someone starts us again.
11398 void ApiTestFuzzer::TearDown() {
11400 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
11401 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
11402 if (fuzzer != NULL) fuzzer->Join();
11407 // Lets not be needlessly self-referential.
11409 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
11410 ApiTestFuzzer::RunAllTests();
11411 ApiTestFuzzer::TearDown();
11416 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
11417 ApiTestFuzzer::RunAllTests();
11418 ApiTestFuzzer::TearDown();
11423 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
11424 ApiTestFuzzer::RunAllTests();
11425 ApiTestFuzzer::TearDown();
11430 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
11431 ApiTestFuzzer::RunAllTests();
11432 ApiTestFuzzer::TearDown();
11436 void ApiTestFuzzer::CallTest() {
11437 v8::Isolate::Scope scope(CcTest::isolate());
11439 printf("Start test %d\n", test_number_);
11440 CallTestNumber(test_number_);
11442 printf("End test %d\n", test_number_);
11446 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
11447 v8::Isolate* isolate = args.GetIsolate();
11448 CHECK(v8::Locker::IsLocked(isolate));
11449 ApiTestFuzzer::Fuzz();
11450 v8::Unlocker unlocker(isolate);
11451 const char* code = "throw 7;";
11453 v8::Locker nested_locker(isolate);
11454 v8::HandleScope scope(isolate);
11455 v8::Handle<Value> exception;
11456 { v8::TryCatch try_catch;
11457 v8::Handle<Value> value = CompileRun(code);
11458 CHECK(value.IsEmpty());
11459 CHECK(try_catch.HasCaught());
11460 // Make sure to wrap the exception in a new handle because
11461 // the handle returned from the TryCatch is destroyed
11462 // when the TryCatch is destroyed.
11463 exception = Local<Value>::New(isolate, try_catch.Exception());
11465 args.GetIsolate()->ThrowException(exception);
11470 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
11471 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
11472 ApiTestFuzzer::Fuzz();
11473 v8::Unlocker unlocker(CcTest::isolate());
11474 const char* code = "throw 7;";
11476 v8::Locker nested_locker(CcTest::isolate());
11477 v8::HandleScope scope(args.GetIsolate());
11478 v8::Handle<Value> value = CompileRun(code);
11479 CHECK(value.IsEmpty());
11480 args.GetReturnValue().Set(v8_str("foo"));
11485 // These are locking tests that don't need to be run again
11486 // as part of the locking aggregation tests.
11487 TEST(NestedLockers) {
11488 v8::Isolate* isolate = CcTest::isolate();
11489 v8::Locker locker(isolate);
11490 CHECK(v8::Locker::IsLocked(isolate));
11492 v8::HandleScope scope(env->GetIsolate());
11493 Local<v8::FunctionTemplate> fun_templ =
11494 v8::FunctionTemplate::New(isolate, ThrowInJS);
11495 Local<Function> fun = fun_templ->GetFunction();
11496 env->Global()->Set(v8_str("throw_in_js"), fun);
11497 Local<Script> script = v8_compile("(function () {"
11505 CHECK_EQ(91, script->Run()->Int32Value());
11509 // These are locking tests that don't need to be run again
11510 // as part of the locking aggregation tests.
11511 TEST(NestedLockersNoTryCatch) {
11512 v8::Locker locker(CcTest::isolate());
11514 v8::HandleScope scope(env->GetIsolate());
11515 Local<v8::FunctionTemplate> fun_templ =
11516 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
11517 Local<Function> fun = fun_templ->GetFunction();
11518 env->Global()->Set(v8_str("throw_in_js"), fun);
11519 Local<Script> script = v8_compile("(function () {"
11527 CHECK_EQ(91, script->Run()->Int32Value());
11531 THREADED_TEST(RecursiveLocking) {
11532 v8::Locker locker(CcTest::isolate());
11534 v8::Locker locker2(CcTest::isolate());
11535 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
11540 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
11541 ApiTestFuzzer::Fuzz();
11542 v8::Unlocker unlocker(CcTest::isolate());
11546 THREADED_TEST(LockUnlockLock) {
11548 v8::Locker locker(CcTest::isolate());
11549 v8::HandleScope scope(CcTest::isolate());
11551 Local<v8::FunctionTemplate> fun_templ =
11552 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
11553 Local<Function> fun = fun_templ->GetFunction();
11554 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11555 Local<Script> script = v8_compile("(function () {"
11556 " unlock_for_a_moment();"
11559 CHECK_EQ(42, script->Run()->Int32Value());
11562 v8::Locker locker(CcTest::isolate());
11563 v8::HandleScope scope(CcTest::isolate());
11565 Local<v8::FunctionTemplate> fun_templ =
11566 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
11567 Local<Function> fun = fun_templ->GetFunction();
11568 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
11569 Local<Script> script = v8_compile("(function () {"
11570 " unlock_for_a_moment();"
11573 CHECK_EQ(42, script->Run()->Int32Value());
11578 static int GetGlobalObjectsCount() {
11580 i::HeapIterator it(CcTest::heap());
11581 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
11582 if (object->IsJSGlobalObject()) count++;
11587 static void CheckSurvivingGlobalObjectsCount(int expected) {
11588 // We need to collect all garbage twice to be sure that everything
11589 // has been collected. This is because inline caches are cleared in
11590 // the first garbage collection but some of the maps have already
11591 // been marked at that point. Therefore some of the maps are not
11592 // collected until the second garbage collection.
11593 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11594 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
11595 int count = GetGlobalObjectsCount();
11597 if (count != expected) CcTest::heap()->TracePathToGlobal();
11599 CHECK_EQ(expected, count);
11603 TEST(DontLeakGlobalObjects) {
11604 // Regression test for issues 1139850 and 1174891.
11606 i::FLAG_expose_gc = true;
11607 v8::V8::Initialize();
11609 for (int i = 0; i < 5; i++) {
11610 { v8::HandleScope scope(CcTest::isolate());
11611 LocalContext context;
11613 CcTest::isolate()->ContextDisposedNotification();
11614 CheckSurvivingGlobalObjectsCount(0);
11616 { v8::HandleScope scope(CcTest::isolate());
11617 LocalContext context;
11618 v8_compile("Date")->Run();
11620 CcTest::isolate()->ContextDisposedNotification();
11621 CheckSurvivingGlobalObjectsCount(0);
11623 { v8::HandleScope scope(CcTest::isolate());
11624 LocalContext context;
11625 v8_compile("/aaa/")->Run();
11627 CcTest::isolate()->ContextDisposedNotification();
11628 CheckSurvivingGlobalObjectsCount(0);
11630 { v8::HandleScope scope(CcTest::isolate());
11631 const char* extension_list[] = { "v8/gc" };
11632 v8::ExtensionConfiguration extensions(1, extension_list);
11633 LocalContext context(&extensions);
11634 v8_compile("gc();")->Run();
11636 CcTest::isolate()->ContextDisposedNotification();
11637 CheckSurvivingGlobalObjectsCount(0);
11642 TEST(CopyablePersistent) {
11643 LocalContext context;
11644 v8::Isolate* isolate = context->GetIsolate();
11645 i::GlobalHandles* globals =
11646 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
11647 int initial_handles = globals->global_handles_count();
11648 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
11651 CopyableObject handle1;
11653 v8::HandleScope scope(isolate);
11654 handle1.Reset(isolate, v8::Object::New(isolate));
11656 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
11657 CopyableObject handle2;
11659 CHECK(handle1 == handle2);
11660 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
11661 CopyableObject handle3(handle2);
11662 CHECK(handle1 == handle3);
11663 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
11665 // Verify autodispose
11666 CHECK_EQ(initial_handles, globals->global_handles_count());
11670 static void WeakApiCallback(
11671 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
11672 Local<Value> value = data.GetValue()->Get(v8_str("key"));
11673 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
11674 data.GetParameter()->Reset();
11675 delete data.GetParameter();
11679 TEST(WeakCallbackApi) {
11680 LocalContext context;
11681 v8::Isolate* isolate = context->GetIsolate();
11682 i::GlobalHandles* globals =
11683 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
11684 int initial_handles = globals->global_handles_count();
11686 v8::HandleScope scope(isolate);
11687 v8::Local<v8::Object> obj = v8::Object::New(isolate);
11688 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
11689 v8::Persistent<v8::Object>* handle =
11690 new v8::Persistent<v8::Object>(isolate, obj);
11691 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
11694 reinterpret_cast<i::Isolate*>(isolate)->heap()->
11695 CollectAllGarbage(i::Heap::kNoGCFlags);
11696 // Verify disposed.
11697 CHECK_EQ(initial_handles, globals->global_handles_count());
11701 v8::Persistent<v8::Object> some_object;
11702 v8::Persistent<v8::Object> bad_handle;
11704 void NewPersistentHandleCallback(
11705 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11706 v8::HandleScope scope(data.GetIsolate());
11707 bad_handle.Reset(data.GetIsolate(), some_object);
11708 data.GetParameter()->Reset();
11712 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
11713 LocalContext context;
11714 v8::Isolate* isolate = context->GetIsolate();
11716 v8::Persistent<v8::Object> handle1, handle2;
11718 v8::HandleScope scope(isolate);
11719 some_object.Reset(isolate, v8::Object::New(isolate));
11720 handle1.Reset(isolate, v8::Object::New(isolate));
11721 handle2.Reset(isolate, v8::Object::New(isolate));
11723 // Note: order is implementation dependent alas: currently
11724 // global handle nodes are processed by PostGarbageCollectionProcessing
11725 // in reverse allocation order, so if second allocated handle is deleted,
11726 // weak callback of the first handle would be able to 'reallocate' it.
11727 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
11729 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11733 v8::Persistent<v8::Object> to_be_disposed;
11735 void DisposeAndForceGcCallback(
11736 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11737 to_be_disposed.Reset();
11738 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11739 data.GetParameter()->Reset();
11743 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
11744 LocalContext context;
11745 v8::Isolate* isolate = context->GetIsolate();
11747 v8::Persistent<v8::Object> handle1, handle2;
11749 v8::HandleScope scope(isolate);
11750 handle1.Reset(isolate, v8::Object::New(isolate));
11751 handle2.Reset(isolate, v8::Object::New(isolate));
11753 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
11754 to_be_disposed.Reset(isolate, handle2);
11755 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11758 void DisposingCallback(
11759 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11760 data.GetParameter()->Reset();
11763 void HandleCreatingCallback(
11764 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
11765 v8::HandleScope scope(data.GetIsolate());
11766 v8::Persistent<v8::Object>(data.GetIsolate(),
11767 v8::Object::New(data.GetIsolate()));
11768 data.GetParameter()->Reset();
11772 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
11773 LocalContext context;
11774 v8::Isolate* isolate = context->GetIsolate();
11776 v8::Persistent<v8::Object> handle1, handle2, handle3;
11778 v8::HandleScope scope(isolate);
11779 handle3.Reset(isolate, v8::Object::New(isolate));
11780 handle2.Reset(isolate, v8::Object::New(isolate));
11781 handle1.Reset(isolate, v8::Object::New(isolate));
11783 handle2.SetWeak(&handle2, DisposingCallback);
11784 handle3.SetWeak(&handle3, HandleCreatingCallback);
11785 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
11789 THREADED_TEST(CheckForCrossContextObjectLiterals) {
11790 v8::V8::Initialize();
11793 const char* sources[nof] = {
11794 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
11798 for (int i = 0; i < nof; i++) {
11799 const char* source = sources[i];
11800 { v8::HandleScope scope(CcTest::isolate());
11801 LocalContext context;
11802 CompileRun(source);
11804 { v8::HandleScope scope(CcTest::isolate());
11805 LocalContext context;
11806 CompileRun(source);
11812 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
11813 v8::EscapableHandleScope inner(env->GetIsolate());
11815 v8::Local<Value> three = v8_num(3);
11816 v8::Local<Value> value = inner.Escape(three);
11822 THREADED_TEST(NestedHandleScopeAndContexts) {
11823 v8::Isolate* isolate = CcTest::isolate();
11824 v8::HandleScope outer(isolate);
11825 v8::Local<Context> env = Context::New(isolate);
11827 v8::Handle<Value> value = NestedScope(env);
11828 v8::Handle<String> str(value->ToString(isolate));
11829 CHECK(!str.IsEmpty());
11834 static bool MatchPointers(void* key1, void* key2) {
11835 return key1 == key2;
11839 struct SymbolInfo {
11846 class SetFunctionEntryHookTest {
11848 SetFunctionEntryHookTest() {
11849 CHECK(instance_ == NULL);
11852 ~SetFunctionEntryHookTest() {
11853 CHECK(instance_ == this);
11858 symbol_locations_.clear();
11859 invocations_.clear();
11862 void OnJitEvent(const v8::JitCodeEvent* event);
11863 static void JitEvent(const v8::JitCodeEvent* event) {
11864 CHECK(instance_ != NULL);
11865 instance_->OnJitEvent(event);
11868 void OnEntryHook(uintptr_t function,
11869 uintptr_t return_addr_location);
11870 static void EntryHook(uintptr_t function,
11871 uintptr_t return_addr_location) {
11872 CHECK(instance_ != NULL);
11873 instance_->OnEntryHook(function, return_addr_location);
11876 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
11877 CHECK(instance_ != NULL);
11878 args.GetReturnValue().Set(v8_num(42));
11880 void RunLoopInNewEnv(v8::Isolate* isolate);
11882 // Records addr as location of symbol.
11883 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
11885 // Finds the symbol containing addr
11886 SymbolInfo* FindSymbolForAddr(i::Address addr);
11887 // Returns the number of invocations where the caller name contains
11888 // \p caller_name and the function name contains \p function_name.
11889 int CountInvocations(const char* caller_name,
11890 const char* function_name);
11892 i::Handle<i::JSFunction> foo_func_;
11893 i::Handle<i::JSFunction> bar_func_;
11895 typedef std::map<size_t, SymbolInfo> SymbolMap;
11896 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
11897 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
11898 SymbolMap symbols_;
11899 SymbolLocationMap symbol_locations_;
11900 InvocationMap invocations_;
11902 static SetFunctionEntryHookTest* instance_;
11904 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
11907 // Returns true if addr is in the range [start, start+len).
11908 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
11909 if (start <= addr && start + len > addr)
11915 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
11916 SymbolInfo* symbol) {
11917 // Insert the symbol at the new location.
11918 SymbolLocationMap::iterator it =
11919 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
11920 // Now erase symbols to the left and right that overlap this one.
11921 while (it != symbol_locations_.begin()) {
11922 SymbolLocationMap::iterator left = it;
11924 if (!Overlaps(left->first, left->second->size, addr))
11926 symbol_locations_.erase(left);
11929 // Now erase symbols to the left and right that overlap this one.
11931 SymbolLocationMap::iterator right = it;
11933 if (right == symbol_locations_.end())
11935 if (!Overlaps(addr, symbol->size, right->first))
11937 symbol_locations_.erase(right);
11942 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
11943 switch (event->type) {
11944 case v8::JitCodeEvent::CODE_ADDED: {
11945 CHECK(event->code_start != NULL);
11946 CHECK_NE(0, static_cast<int>(event->code_len));
11947 CHECK(event->name.str != NULL);
11948 size_t symbol_id = symbols_.size();
11950 // Record the new symbol.
11951 SymbolInfo& info = symbols_[symbol_id];
11952 info.id = symbol_id;
11953 info.size = event->code_len;
11954 info.name.assign(event->name.str, event->name.str + event->name.len);
11956 // And record it's location.
11957 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
11961 case v8::JitCodeEvent::CODE_MOVED: {
11962 // We would like to never see code move that we haven't seen before,
11963 // but the code creation event does not happen until the line endings
11964 // have been calculated (this is so that we can report the line in the
11965 // script at which the function source is found, see
11966 // Compiler::RecordFunctionCompilation) and the line endings
11967 // calculations can cause a GC, which can move the newly created code
11968 // before its existence can be logged.
11969 SymbolLocationMap::iterator it(
11970 symbol_locations_.find(
11971 reinterpret_cast<i::Address>(event->code_start)));
11972 if (it != symbol_locations_.end()) {
11973 // Found a symbol at this location, move it.
11974 SymbolInfo* info = it->second;
11975 symbol_locations_.erase(it);
11976 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
11985 void SetFunctionEntryHookTest::OnEntryHook(
11986 uintptr_t function, uintptr_t return_addr_location) {
11987 // Get the function's code object.
11988 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
11989 reinterpret_cast<i::Address>(function));
11990 CHECK(function_code != NULL);
11992 // Then try and look up the caller's code object.
11993 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
11995 // Count the invocation.
11996 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
11997 SymbolInfo* function_symbol =
11998 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
11999 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
12001 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
12002 // Check that we have a symbol for the "bar" function at the right location.
12003 SymbolLocationMap::iterator it(
12004 symbol_locations_.find(function_code->instruction_start()));
12005 CHECK(it != symbol_locations_.end());
12008 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
12009 // Check that we have a symbol for "foo" at the right location.
12010 SymbolLocationMap::iterator it(
12011 symbol_locations_.find(function_code->instruction_start()));
12012 CHECK(it != symbol_locations_.end());
12017 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
12018 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
12019 // Do we have a direct hit on a symbol?
12020 if (it != symbol_locations_.end()) {
12021 if (it->first == addr)
12025 // If not a direct hit, it'll have to be the previous symbol.
12026 if (it == symbol_locations_.begin())
12030 size_t offs = addr - it->first;
12031 if (offs < it->second->size)
12038 int SetFunctionEntryHookTest::CountInvocations(
12039 const char* caller_name, const char* function_name) {
12040 InvocationMap::iterator it(invocations_.begin());
12041 int invocations = 0;
12042 for (; it != invocations_.end(); ++it) {
12043 SymbolInfo* caller = it->first.first;
12044 SymbolInfo* function = it->first.second;
12046 // Filter out non-matching functions.
12047 if (function_name != NULL) {
12048 if (function->name.find(function_name) == std::string::npos)
12052 // Filter out non-matching callers.
12053 if (caller_name != NULL) {
12054 if (caller == NULL)
12056 if (caller->name.find(caller_name) == std::string::npos)
12060 // It matches add the invocation count to the tally.
12061 invocations += it->second;
12064 return invocations;
12068 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
12069 v8::HandleScope outer(isolate);
12070 v8::Local<Context> env = Context::New(isolate);
12073 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
12074 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
12075 env->Global()->Set(v8_str("obj"), t->NewInstance());
12077 const char* script =
12078 "function bar() {\n"
12080 " for (i = 0; i < 100; ++i)\n"
12084 "function foo(i) { return i * i; }\n"
12085 "// Invoke on the runtime function.\n"
12087 CompileRun(script);
12088 bar_func_ = i::Handle<i::JSFunction>::cast(
12089 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
12090 DCHECK(!bar_func_.is_null());
12093 i::Handle<i::JSFunction>::cast(
12094 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
12095 DCHECK(!foo_func_.is_null());
12097 v8::Handle<v8::Value> value = CompileRun("bar();");
12098 CHECK(value->IsNumber());
12099 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12101 // Test the optimized codegen path.
12102 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
12104 CHECK(value->IsNumber());
12105 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
12111 void SetFunctionEntryHookTest::RunTest() {
12112 // Work in a new isolate throughout.
12113 v8::Isolate::CreateParams create_params;
12114 create_params.entry_hook = EntryHook;
12115 create_params.code_event_handler = JitEvent;
12116 v8::Isolate* isolate = v8::Isolate::New(create_params);
12119 v8::Isolate::Scope scope(isolate);
12121 RunLoopInNewEnv(isolate);
12123 // Check the exepected invocation counts.
12124 CHECK_EQ(2, CountInvocations(NULL, "bar"));
12125 CHECK_EQ(200, CountInvocations("bar", "foo"));
12126 CHECK_EQ(200, CountInvocations(NULL, "foo"));
12128 // Verify that we have an entry hook on some specific stubs.
12129 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
12130 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
12131 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
12133 isolate->Dispose();
12137 // Make sure a second isolate is unaffected by the previous entry hook.
12138 isolate = v8::Isolate::New();
12140 v8::Isolate::Scope scope(isolate);
12142 // Reset the entry count to zero and set the entry hook.
12143 RunLoopInNewEnv(isolate);
12145 // We should record no invocations in this isolate.
12146 CHECK_EQ(0, static_cast<int>(invocations_.size()));
12149 isolate->Dispose();
12153 TEST(SetFunctionEntryHook) {
12154 // FunctionEntryHook does not work well with experimental natives.
12155 // Experimental natives are compiled during snapshot deserialization.
12156 // This test breaks because InstallGetter (function from snapshot that
12157 // only gets called from experimental natives) is compiled with entry hooks.
12158 i::FLAG_allow_natives_syntax = true;
12159 i::FLAG_use_inlining = false;
12161 SetFunctionEntryHookTest test;
12166 static i::HashMap* code_map = NULL;
12167 static i::HashMap* jitcode_line_info = NULL;
12168 static int saw_bar = 0;
12169 static int move_events = 0;
12172 static bool FunctionNameIs(const char* expected,
12173 const v8::JitCodeEvent* event) {
12174 // Log lines for functions are of the general form:
12175 // "LazyCompile:<type><function_name>", where the type is one of
12177 static const char kPreamble[] = "LazyCompile:";
12178 static size_t kPreambleLen = sizeof(kPreamble) - 1;
12180 if (event->name.len < sizeof(kPreamble) - 1 ||
12181 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
12185 const char* tail = event->name.str + kPreambleLen;
12186 size_t tail_len = event->name.len - kPreambleLen;
12187 size_t expected_len = strlen(expected);
12188 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
12193 // Check for tails like 'bar :1'.
12194 if (tail_len > expected_len + 2 &&
12195 tail[expected_len] == ' ' &&
12196 tail[expected_len + 1] == ':' &&
12197 tail[expected_len + 2] &&
12198 !strncmp(tail, expected, expected_len)) {
12202 if (tail_len != expected_len)
12205 return strncmp(tail, expected, expected_len) == 0;
12209 static void event_handler(const v8::JitCodeEvent* event) {
12210 CHECK(event != NULL);
12211 CHECK(code_map != NULL);
12212 CHECK(jitcode_line_info != NULL);
12214 class DummyJitCodeLineInfo {
12217 switch (event->type) {
12218 case v8::JitCodeEvent::CODE_ADDED: {
12219 CHECK(event->code_start != NULL);
12220 CHECK_NE(0, static_cast<int>(event->code_len));
12221 CHECK(event->name.str != NULL);
12222 i::HashMap::Entry* entry =
12223 code_map->Lookup(event->code_start,
12224 i::ComputePointerHash(event->code_start),
12226 entry->value = reinterpret_cast<void*>(event->code_len);
12228 if (FunctionNameIs("bar", event)) {
12234 case v8::JitCodeEvent::CODE_MOVED: {
12235 uint32_t hash = i::ComputePointerHash(event->code_start);
12236 // We would like to never see code move that we haven't seen before,
12237 // but the code creation event does not happen until the line endings
12238 // have been calculated (this is so that we can report the line in the
12239 // script at which the function source is found, see
12240 // Compiler::RecordFunctionCompilation) and the line endings
12241 // calculations can cause a GC, which can move the newly created code
12242 // before its existence can be logged.
12243 i::HashMap::Entry* entry =
12244 code_map->Lookup(event->code_start, hash, false);
12245 if (entry != NULL) {
12248 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
12249 code_map->Remove(event->code_start, hash);
12251 entry = code_map->Lookup(event->new_code_start,
12252 i::ComputePointerHash(event->new_code_start),
12254 CHECK(entry != NULL);
12255 entry->value = reinterpret_cast<void*>(event->code_len);
12260 case v8::JitCodeEvent::CODE_REMOVED:
12261 // Object/code removal events are currently not dispatched from the GC.
12265 // For CODE_START_LINE_INFO_RECORDING event, we will create one
12266 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
12267 // record it in jitcode_line_info.
12268 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
12269 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
12270 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
12271 temp_event->user_data = line_info;
12272 i::HashMap::Entry* entry =
12273 jitcode_line_info->Lookup(line_info,
12274 i::ComputePointerHash(line_info),
12276 entry->value = reinterpret_cast<void*>(line_info);
12279 // For these two events, we will check whether the event->user_data
12280 // data structure is created before during CODE_START_LINE_INFO_RECORDING
12281 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
12282 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
12283 CHECK(event->user_data != NULL);
12284 uint32_t hash = i::ComputePointerHash(event->user_data);
12285 i::HashMap::Entry* entry =
12286 jitcode_line_info->Lookup(event->user_data, hash, false);
12287 CHECK(entry != NULL);
12288 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
12292 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
12293 CHECK(event->user_data != NULL);
12294 uint32_t hash = i::ComputePointerHash(event->user_data);
12295 i::HashMap::Entry* entry =
12296 jitcode_line_info->Lookup(event->user_data, hash, false);
12297 CHECK(entry != NULL);
12302 // Impossible event.
12309 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
12310 i::FLAG_stress_compaction = true;
12311 i::FLAG_incremental_marking = false;
12312 if (i::FLAG_never_compact) return;
12313 const char* script =
12316 " for (i = 0; i < 10; ++i)"
12320 "function foo(i) { return i; };"
12323 // Run this test in a new isolate to make sure we don't
12324 // have remnants of state from other code.
12325 v8::Isolate* isolate = v8::Isolate::New();
12327 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
12328 i::Heap* heap = i_isolate->heap();
12330 // Start with a clean slate.
12331 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Prepare");
12334 v8::HandleScope scope(isolate);
12335 i::HashMap code(MatchPointers);
12338 i::HashMap lineinfo(MatchPointers);
12339 jitcode_line_info = &lineinfo;
12344 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
12346 // Generate new code objects sparsely distributed across several
12347 // different fragmented code-space pages.
12348 const int kIterations = 10;
12349 for (int i = 0; i < kIterations; ++i) {
12350 LocalContext env(isolate);
12351 i::AlwaysAllocateScope always_allocate(i_isolate);
12352 SimulateFullSpace(heap->code_space());
12353 CompileRun(script);
12355 // Keep a strong reference to the code object in the handle scope.
12356 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
12357 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
12358 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
12359 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
12361 // Clear the compilation cache to get more wastage.
12362 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
12365 // Force code movement.
12366 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler_Move");
12368 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
12370 CHECK_LE(kIterations, saw_bar);
12371 CHECK_LT(0, move_events);
12374 jitcode_line_info = NULL;
12378 isolate->Dispose();
12380 // Do this in a new isolate.
12381 isolate = v8::Isolate::New();
12384 // Verify that we get callbacks for existing code objects when we
12385 // request enumeration of existing code.
12387 v8::HandleScope scope(isolate);
12388 LocalContext env(isolate);
12389 CompileRun(script);
12391 // Now get code through initial iteration.
12392 i::HashMap code(MatchPointers);
12395 i::HashMap lineinfo(MatchPointers);
12396 jitcode_line_info = &lineinfo;
12398 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
12400 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
12402 jitcode_line_info = NULL;
12403 // We expect that we got some events. Note that if we could get code removal
12404 // notifications, we could compare two collections, one created by listening
12405 // from the time of creation of an isolate, and the other by subscribing
12406 // with EnumExisting.
12407 CHECK_LT(0u, code.occupancy());
12413 isolate->Dispose();
12417 THREADED_TEST(ExternalAllocatedMemory) {
12418 v8::Isolate* isolate = CcTest::isolate();
12419 v8::HandleScope outer(isolate);
12420 v8::Local<Context> env(Context::New(isolate));
12421 CHECK(!env.IsEmpty());
12422 const int64_t kSize = 1024*1024;
12423 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
12424 CHECK_EQ(baseline + kSize,
12425 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
12427 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
12428 const int64_t kTriggerGCSize =
12429 v8::internal::Internals::kExternalAllocationLimit + 1;
12430 CHECK_EQ(baseline + kTriggerGCSize,
12431 isolate->AdjustAmountOfExternalAllocatedMemory(kTriggerGCSize));
12433 isolate->AdjustAmountOfExternalAllocatedMemory(-kTriggerGCSize));
12437 // Regression test for issue 54, object templates with internal fields
12438 // but no accessors or interceptors did not get their internal field
12439 // count set on instances.
12440 THREADED_TEST(Regress54) {
12441 LocalContext context;
12442 v8::Isolate* isolate = context->GetIsolate();
12443 v8::HandleScope outer(isolate);
12444 static v8::Persistent<v8::ObjectTemplate> templ;
12445 if (templ.IsEmpty()) {
12446 v8::EscapableHandleScope inner(isolate);
12447 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
12448 local->SetInternalFieldCount(1);
12449 templ.Reset(isolate, inner.Escape(local));
12451 v8::Handle<v8::Object> result =
12452 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
12453 CHECK_EQ(1, result->InternalFieldCount());
12457 // If part of the threaded tests, this test makes ThreadingTest fail
12459 TEST(CatchStackOverflow) {
12460 LocalContext context;
12461 v8::HandleScope scope(context->GetIsolate());
12462 v8::TryCatch try_catch;
12463 v8::Handle<v8::Value> result = CompileRun(
12469 CHECK(result.IsEmpty());
12473 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
12474 const char* resource_name,
12476 v8::HandleScope scope(CcTest::isolate());
12477 v8::TryCatch try_catch;
12478 v8::Handle<v8::Value> result = script->Run();
12479 CHECK(result.IsEmpty());
12480 CHECK(try_catch.HasCaught());
12481 v8::Handle<v8::Message> message = try_catch.Message();
12482 CHECK(!message.IsEmpty());
12483 CHECK_EQ(10 + line_offset, message->GetLineNumber());
12484 CHECK_EQ(91, message->GetStartPosition());
12485 CHECK_EQ(92, message->GetEndPosition());
12486 CHECK_EQ(2, message->GetStartColumn());
12487 CHECK_EQ(3, message->GetEndColumn());
12488 v8::String::Utf8Value line(message->GetSourceLine());
12489 CHECK_EQ(0, strcmp(" throw 'nirk';", *line));
12490 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
12491 CHECK_EQ(0, strcmp(resource_name, *name));
12495 THREADED_TEST(TryCatchSourceInfo) {
12496 LocalContext context;
12497 v8::HandleScope scope(context->GetIsolate());
12498 v8::Local<v8::String> source = v8_str(
12499 "function Foo() {\n"
12503 "function Bar() {\n"
12507 "function Baz() {\n"
12513 const char* resource_name;
12514 v8::Handle<v8::Script> script;
12515 resource_name = "test.js";
12516 script = CompileWithOrigin(source, resource_name);
12517 CheckTryCatchSourceInfo(script, resource_name, 0);
12519 resource_name = "test1.js";
12520 v8::ScriptOrigin origin1(
12521 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
12522 script = v8::Script::Compile(source, &origin1);
12523 CheckTryCatchSourceInfo(script, resource_name, 0);
12525 resource_name = "test2.js";
12526 v8::ScriptOrigin origin2(
12527 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
12528 v8::Integer::New(context->GetIsolate(), 7));
12529 script = v8::Script::Compile(source, &origin2);
12530 CheckTryCatchSourceInfo(script, resource_name, 7);
12534 THREADED_TEST(CompilationCache) {
12535 LocalContext context;
12536 v8::HandleScope scope(context->GetIsolate());
12537 v8::Handle<v8::String> source0 =
12538 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
12539 v8::Handle<v8::String> source1 =
12540 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
12541 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
12542 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
12543 v8::Handle<v8::Script> script2 =
12544 v8::Script::Compile(source0); // different origin
12545 CHECK_EQ(1234, script0->Run()->Int32Value());
12546 CHECK_EQ(1234, script1->Run()->Int32Value());
12547 CHECK_EQ(1234, script2->Run()->Int32Value());
12551 static void FunctionNameCallback(
12552 const v8::FunctionCallbackInfo<v8::Value>& args) {
12553 ApiTestFuzzer::Fuzz();
12554 args.GetReturnValue().Set(v8_num(42));
12558 THREADED_TEST(CallbackFunctionName) {
12559 LocalContext context;
12560 v8::Isolate* isolate = context->GetIsolate();
12561 v8::HandleScope scope(isolate);
12562 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
12563 t->Set(v8_str("asdf"),
12564 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
12565 context->Global()->Set(v8_str("obj"), t->NewInstance());
12566 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
12567 CHECK(value->IsString());
12568 v8::String::Utf8Value name(value);
12569 CHECK_EQ(0, strcmp("asdf", *name));
12573 THREADED_TEST(DateAccess) {
12574 LocalContext context;
12575 v8::HandleScope scope(context->GetIsolate());
12576 v8::Handle<v8::Value> date =
12577 v8::Date::New(context->GetIsolate(), 1224744689038.0);
12578 CHECK(date->IsDate());
12579 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
12583 void CheckProperties(v8::Isolate* isolate, v8::Handle<v8::Value> val,
12584 unsigned elmc, const char* elmv[]) {
12585 v8::Handle<v8::Object> obj = val.As<v8::Object>();
12586 v8::Handle<v8::Array> props = obj->GetPropertyNames();
12587 CHECK_EQ(elmc, props->Length());
12588 for (unsigned i = 0; i < elmc; i++) {
12589 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
12590 CHECK_EQ(0, strcmp(elmv[i], *elm));
12595 void CheckOwnProperties(v8::Isolate* isolate, v8::Handle<v8::Value> val,
12596 unsigned elmc, const char* elmv[]) {
12597 v8::Handle<v8::Object> obj = val.As<v8::Object>();
12598 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
12599 CHECK_EQ(elmc, props->Length());
12600 for (unsigned i = 0; i < elmc; i++) {
12601 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
12602 CHECK_EQ(0, strcmp(elmv[i], *elm));
12607 THREADED_TEST(PropertyEnumeration) {
12608 LocalContext context;
12609 v8::Isolate* isolate = context->GetIsolate();
12610 v8::HandleScope scope(isolate);
12611 v8::Handle<v8::Value> obj = CompileRun(
12614 "result[1] = {a: 1, b: 2};"
12615 "result[2] = [1, 2, 3];"
12616 "var proto = {x: 1, y: 2, z: 3};"
12617 "var x = { __proto__: proto, w: 0, z: 1 };"
12620 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12621 CHECK_EQ(4u, elms->Length());
12623 const char** elmv0 = NULL;
12625 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12626 CheckOwnProperties(
12627 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12629 const char* elmv1[] = {"a", "b"};
12631 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
12632 CheckOwnProperties(
12633 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
12635 const char* elmv2[] = {"0", "1", "2"};
12637 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
12638 CheckOwnProperties(
12639 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
12641 const char* elmv3[] = {"w", "z", "x", "y"};
12643 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
12645 const char* elmv4[] = {"w", "z"};
12646 CheckOwnProperties(
12647 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
12651 THREADED_TEST(PropertyEnumeration2) {
12652 LocalContext context;
12653 v8::Isolate* isolate = context->GetIsolate();
12654 v8::HandleScope scope(isolate);
12655 v8::Handle<v8::Value> obj = CompileRun(
12658 "result[1] = {a: 1, b: 2};"
12659 "result[2] = [1, 2, 3];"
12660 "var proto = {x: 1, y: 2, z: 3};"
12661 "var x = { __proto__: proto, w: 0, z: 1 };"
12664 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
12665 CHECK_EQ(4u, elms->Length());
12667 const char** elmv0 = NULL;
12668 CheckProperties(isolate,
12669 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
12671 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
12672 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
12673 CHECK_EQ(0u, props->Length());
12674 for (uint32_t i = 0; i < props->Length(); i++) {
12675 printf("p[%u]\n", i);
12679 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
12681 v8::AccessType type,
12682 Local<Value> data) {
12683 return type != v8::ACCESS_SET;
12687 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
12689 v8::AccessType type,
12690 Local<Value> data) {
12691 return type != v8::ACCESS_SET;
12695 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
12696 LocalContext context;
12697 v8::Isolate* isolate = context->GetIsolate();
12698 v8::HandleScope scope(isolate);
12699 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
12700 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
12701 IndexedSetAccessBlocker);
12702 templ->Set(v8_str("x"), v8::True(isolate));
12703 Local<v8::Object> instance = templ->NewInstance();
12704 context->Global()->Set(v8_str("obj"), instance);
12705 Local<Value> value = CompileRun("obj.x");
12706 CHECK(value->BooleanValue());
12710 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
12712 v8::AccessType type,
12713 Local<Value> data) {
12718 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
12720 v8::AccessType type,
12721 Local<Value> data) {
12727 THREADED_TEST(AccessChecksReenabledCorrectly) {
12728 LocalContext context;
12729 v8::Isolate* isolate = context->GetIsolate();
12730 v8::HandleScope scope(isolate);
12731 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
12732 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
12733 IndexedGetAccessBlocker);
12734 templ->Set(v8_str("a"), v8_str("a"));
12735 // Add more than 8 (see kMaxFastProperties) properties
12736 // so that the constructor will force copying map.
12737 // Cannot sprintf, gcc complains unsafety.
12739 for (char i = '0'; i <= '9' ; i++) {
12741 for (char j = '0'; j <= '9'; j++) {
12743 for (char k = '0'; k <= '9'; k++) {
12746 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
12751 Local<v8::Object> instance_1 = templ->NewInstance();
12752 context->Global()->Set(v8_str("obj_1"), instance_1);
12754 Local<Value> value_1 = CompileRun("obj_1.a");
12755 CHECK(value_1.IsEmpty());
12757 Local<v8::Object> instance_2 = templ->NewInstance();
12758 context->Global()->Set(v8_str("obj_2"), instance_2);
12760 Local<Value> value_2 = CompileRun("obj_2.a");
12761 CHECK(value_2.IsEmpty());
12765 // This tests that access check information remains on the global
12766 // object template when creating contexts.
12767 THREADED_TEST(AccessControlRepeatedContextCreation) {
12768 v8::Isolate* isolate = CcTest::isolate();
12769 v8::HandleScope handle_scope(isolate);
12770 v8::Handle<v8::ObjectTemplate> global_template =
12771 v8::ObjectTemplate::New(isolate);
12772 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
12773 IndexedSetAccessBlocker);
12774 i::Handle<i::ObjectTemplateInfo> internal_template =
12775 v8::Utils::OpenHandle(*global_template);
12776 CHECK(!internal_template->constructor()->IsUndefined());
12777 i::Handle<i::FunctionTemplateInfo> constructor(
12778 i::FunctionTemplateInfo::cast(internal_template->constructor()));
12779 CHECK(!constructor->access_check_info()->IsUndefined());
12780 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
12781 CHECK(!context0.IsEmpty());
12782 CHECK(!constructor->access_check_info()->IsUndefined());
12786 THREADED_TEST(TurnOnAccessCheck) {
12787 v8::Isolate* isolate = CcTest::isolate();
12788 v8::HandleScope handle_scope(isolate);
12790 // Create an environment with access check to the global object disabled by
12792 v8::Handle<v8::ObjectTemplate> global_template =
12793 v8::ObjectTemplate::New(isolate);
12794 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
12795 IndexedGetAccessBlocker,
12796 v8::Handle<v8::Value>(),
12798 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
12799 Context::Scope context_scope(context);
12801 // Set up a property and a number of functions.
12802 context->Global()->Set(v8_str("a"), v8_num(1));
12803 CompileRun("function f1() {return a;}"
12804 "function f2() {return a;}"
12805 "function g1() {return h();}"
12806 "function g2() {return h();}"
12807 "function h() {return 1;}");
12808 Local<Function> f1 =
12809 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12810 Local<Function> f2 =
12811 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12812 Local<Function> g1 =
12813 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12814 Local<Function> g2 =
12815 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12816 Local<Function> h =
12817 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
12819 // Get the global object.
12820 v8::Handle<v8::Object> global = context->Global();
12822 // Call f1 one time and f2 a number of times. This will ensure that f1 still
12823 // uses the runtime system to retreive property a whereas f2 uses global load
12825 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
12826 for (int i = 0; i < 4; i++) {
12827 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12830 // Same for g1 and g2.
12831 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12832 for (int i = 0; i < 4; i++) {
12833 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12836 // Detach the global and turn on access check.
12837 Local<Object> hidden_global = Local<Object>::Cast(
12838 context->Global()->GetPrototype());
12839 context->DetachGlobal();
12840 hidden_global->TurnOnAccessCheck();
12842 // Failing access check results in exception.
12843 CHECK(f1->Call(global, 0, NULL).IsEmpty());
12844 CHECK(f2->Call(global, 0, NULL).IsEmpty());
12845 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12846 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12848 // No failing access check when just returning a constant.
12849 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12853 static const char* kPropertyA = "a";
12854 static const char* kPropertyH = "h";
12856 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
12858 v8::AccessType type,
12859 Local<Value> data) {
12860 if (!name->IsString()) return false;
12861 i::Handle<i::String> name_handle =
12862 v8::Utils::OpenHandle(String::Cast(*name));
12863 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
12864 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
12868 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
12869 v8::Isolate* isolate = CcTest::isolate();
12870 v8::HandleScope handle_scope(isolate);
12872 // Create an environment with access check to the global object disabled by
12873 // default. When the registered access checker will block access to properties
12875 v8::Handle<v8::ObjectTemplate> global_template =
12876 v8::ObjectTemplate::New(isolate);
12877 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
12878 IndexedGetAccessBlocker,
12879 v8::Handle<v8::Value>(),
12881 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
12882 Context::Scope context_scope(context);
12884 // Set up a property and a number of functions.
12885 context->Global()->Set(v8_str("a"), v8_num(1));
12886 static const char* source = "function f1() {return a;}"
12887 "function f2() {return a;}"
12888 "function g1() {return h();}"
12889 "function g2() {return h();}"
12890 "function h() {return 1;}";
12892 CompileRun(source);
12893 Local<Function> f1;
12894 Local<Function> f2;
12895 Local<Function> g1;
12896 Local<Function> g2;
12898 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
12899 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
12900 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
12901 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
12902 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
12904 // Get the global object.
12905 v8::Handle<v8::Object> global = context->Global();
12907 // Call f1 one time and f2 a number of times. This will ensure that f1 still
12908 // uses the runtime system to retreive property a whereas f2 uses global load
12910 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
12911 for (int i = 0; i < 4; i++) {
12912 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
12915 // Same for g1 and g2.
12916 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
12917 for (int i = 0; i < 4; i++) {
12918 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
12921 // Detach the global and turn on access check now blocking access to property
12922 // a and function h.
12923 Local<Object> hidden_global = Local<Object>::Cast(
12924 context->Global()->GetPrototype());
12925 context->DetachGlobal();
12926 hidden_global->TurnOnAccessCheck();
12928 // Failing access check results in exception.
12929 CHECK(f1->Call(global, 0, NULL).IsEmpty());
12930 CHECK(f2->Call(global, 0, NULL).IsEmpty());
12931 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12932 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12934 // No failing access check when just returning a constant.
12935 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
12937 // Now compile the source again. And get the newly compiled functions, except
12938 // for h for which access is blocked.
12939 CompileRun(source);
12940 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
12941 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
12942 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
12943 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
12944 CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
12946 // Failing access check results in exception.
12947 v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
12948 CHECK(result.IsEmpty());
12949 CHECK(f1->Call(global, 0, NULL).IsEmpty());
12950 CHECK(f2->Call(global, 0, NULL).IsEmpty());
12951 CHECK(g1->Call(global, 0, NULL).IsEmpty());
12952 CHECK(g2->Call(global, 0, NULL).IsEmpty());
12956 // Tests that ScriptData can be serialized and deserialized.
12957 TEST(PreCompileSerialization) {
12958 v8::V8::Initialize();
12960 v8::Isolate* isolate = env->GetIsolate();
12961 HandleScope handle_scope(isolate);
12963 i::FLAG_min_preparse_length = 0;
12964 const char* script = "function foo(a) { return a+1; }";
12965 v8::ScriptCompiler::Source source(v8_str(script));
12966 v8::ScriptCompiler::Compile(isolate, &source,
12967 v8::ScriptCompiler::kProduceParserCache);
12969 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
12970 i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
12971 i::MemCopy(serialized_data, cd->data, cd->length);
12974 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
12976 // Verify that the original is the same as the deserialized.
12977 CHECK_EQ(cd->length, deserialized->length());
12978 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
12980 delete deserialized;
12981 i::DeleteArray(serialized_data);
12985 // This tests that we do not allow dictionary load/call inline caches
12986 // to use functions that have not yet been compiled. The potential
12987 // problem of loading a function that has not yet been compiled can
12988 // arise because we share code between contexts via the compilation
12990 THREADED_TEST(DictionaryICLoadedFunction) {
12991 v8::HandleScope scope(CcTest::isolate());
12993 for (int i = 0; i < 2; i++) {
12994 LocalContext context;
12995 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
12996 context->Global()->Delete(v8_str("tmp"));
12997 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
13000 for (int i = 0; i < 2; i++) {
13001 LocalContext context;
13002 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
13003 context->Global()->Delete(v8_str("tmp"));
13004 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
13009 // Test that cross-context new calls use the context of the callee to
13010 // create the new JavaScript object.
13011 THREADED_TEST(CrossContextNew) {
13012 v8::Isolate* isolate = CcTest::isolate();
13013 v8::HandleScope scope(isolate);
13014 v8::Local<Context> context0 = Context::New(isolate);
13015 v8::Local<Context> context1 = Context::New(isolate);
13017 // Allow cross-domain access.
13018 Local<String> token = v8_str("<security token>");
13019 context0->SetSecurityToken(token);
13020 context1->SetSecurityToken(token);
13022 // Set an 'x' property on the Object prototype and define a
13023 // constructor function in context0.
13025 CompileRun("Object.prototype.x = 42; function C() {};");
13028 // Call the constructor function from context0 and check that the
13029 // result has the 'x' property.
13031 context1->Global()->Set(v8_str("other"), context0->Global());
13032 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
13033 CHECK(value->IsInt32());
13034 CHECK_EQ(42, value->Int32Value());
13039 // Verify that we can clone an object
13040 TEST(ObjectClone) {
13042 v8::Isolate* isolate = env->GetIsolate();
13043 v8::HandleScope scope(isolate);
13045 const char* sample =
13047 "rv.alpha = 'hello';" \
13051 // Create an object, verify basics.
13052 Local<Value> val = CompileRun(sample);
13053 CHECK(val->IsObject());
13054 Local<v8::Object> obj = val.As<v8::Object>();
13055 obj->Set(v8_str("gamma"), v8_str("cloneme"));
13057 CHECK(v8_str("hello")->Equals(obj->Get(v8_str("alpha"))));
13058 CHECK(v8::Integer::New(isolate, 123)->Equals(obj->Get(v8_str("beta"))));
13059 CHECK(v8_str("cloneme")->Equals(obj->Get(v8_str("gamma"))));
13062 Local<v8::Object> clone = obj->Clone();
13063 CHECK(v8_str("hello")->Equals(clone->Get(v8_str("alpha"))));
13064 CHECK(v8::Integer::New(isolate, 123)->Equals(clone->Get(v8_str("beta"))));
13065 CHECK(v8_str("cloneme")->Equals(clone->Get(v8_str("gamma"))));
13067 // Set a property on the clone, verify each object.
13068 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
13069 CHECK(v8::Integer::New(isolate, 123)->Equals(obj->Get(v8_str("beta"))));
13070 CHECK(v8::Integer::New(isolate, 456)->Equals(clone->Get(v8_str("beta"))));
13074 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
13076 explicit OneByteVectorResource(i::Vector<const char> vector)
13078 virtual ~OneByteVectorResource() {}
13079 virtual size_t length() const { return data_.length(); }
13080 virtual const char* data() const { return data_.start(); }
13082 i::Vector<const char> data_;
13086 class UC16VectorResource : public v8::String::ExternalStringResource {
13088 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
13090 virtual ~UC16VectorResource() {}
13091 virtual size_t length() const { return data_.length(); }
13092 virtual const i::uc16* data() const { return data_.start(); }
13094 i::Vector<const i::uc16> data_;
13098 static void MorphAString(i::String* string,
13099 OneByteVectorResource* one_byte_resource,
13100 UC16VectorResource* uc16_resource) {
13101 CHECK(i::StringShape(string).IsExternal());
13102 if (string->IsOneByteRepresentation()) {
13103 // Check old map is not internalized or long.
13104 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
13105 // Morph external string to be TwoByte string.
13106 string->set_map(CcTest::heap()->external_string_map());
13107 i::ExternalTwoByteString* morphed =
13108 i::ExternalTwoByteString::cast(string);
13109 morphed->set_resource(uc16_resource);
13111 // Check old map is not internalized or long.
13112 CHECK(string->map() == CcTest::heap()->external_string_map());
13113 // Morph external string to be one-byte string.
13114 string->set_map(CcTest::heap()->external_one_byte_string_map());
13115 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
13116 morphed->set_resource(one_byte_resource);
13121 // Test that we can still flatten a string if the components it is built up
13122 // from have been turned into 16 bit strings in the mean time.
13123 THREADED_TEST(MorphCompositeStringTest) {
13124 char utf_buffer[129];
13125 const char* c_string = "Now is the time for all good men"
13126 " to come to the aid of the party";
13127 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
13130 i::Factory* factory = CcTest::i_isolate()->factory();
13131 v8::HandleScope scope(env->GetIsolate());
13132 OneByteVectorResource one_byte_resource(
13133 i::Vector<const char>(c_string, i::StrLength(c_string)));
13134 UC16VectorResource uc16_resource(
13135 i::Vector<const uint16_t>(two_byte_string,
13136 i::StrLength(c_string)));
13139 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
13140 &one_byte_resource).ToHandleChecked()));
13142 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
13143 &one_byte_resource).ToHandleChecked()));
13145 env->Global()->Set(v8_str("lhs"), lhs);
13146 env->Global()->Set(v8_str("rhs"), rhs);
13149 "var cons = lhs + rhs;"
13150 "var slice = lhs.substring(1, lhs.length - 1);"
13151 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
13153 CHECK(lhs->IsOneByte());
13154 CHECK(rhs->IsOneByte());
13156 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
13158 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
13161 // This should UTF-8 without flattening, since everything is ASCII.
13162 Handle<String> cons = v8_compile("cons")->Run().As<String>();
13163 CHECK_EQ(128, cons->Utf8Length());
13165 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
13166 CHECK_EQ(128, nchars);
13167 CHECK_EQ(0, strcmp(
13169 "Now is the time for all good men to come to the aid of the party"
13170 "Now is the time for all good men to come to the aid of the party"));
13172 // Now do some stuff to make sure the strings are flattened, etc.
13174 "/[^a-z]/.test(cons);"
13175 "/[^a-z]/.test(slice);"
13176 "/[^a-z]/.test(slice_on_cons);");
13177 const char* expected_cons =
13178 "Now is the time for all good men to come to the aid of the party"
13179 "Now is the time for all good men to come to the aid of the party";
13180 const char* expected_slice =
13181 "ow is the time for all good men to come to the aid of the part";
13182 const char* expected_slice_on_cons =
13183 "ow is the time for all good men to come to the aid of the party"
13184 "Now is the time for all good men to come to the aid of the part";
13185 CHECK(String::NewFromUtf8(env->GetIsolate(), expected_cons)
13186 ->Equals(env->Global()->Get(v8_str("cons"))));
13187 CHECK(String::NewFromUtf8(env->GetIsolate(), expected_slice)
13188 ->Equals(env->Global()->Get(v8_str("slice"))));
13189 CHECK(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons)
13190 ->Equals(env->Global()->Get(v8_str("slice_on_cons"))));
13192 i::DeleteArray(two_byte_string);
13196 TEST(CompileExternalTwoByteSource) {
13197 LocalContext context;
13198 v8::HandleScope scope(context->GetIsolate());
13200 // This is a very short list of sources, which currently is to check for a
13201 // regression caused by r2703.
13202 const char* one_byte_sources[] = {
13204 "-0.5", // This mainly testes PushBack in the Scanner.
13205 "--0.5", // This mainly testes PushBack in the Scanner.
13208 // Compile the sources as external two byte strings.
13209 for (int i = 0; one_byte_sources[i] != NULL; i++) {
13210 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
13211 TestResource* uc16_resource = new TestResource(two_byte_string);
13212 v8::Local<v8::String> source =
13213 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
13214 v8::Script::Compile(source);
13219 #ifndef V8_INTERPRETED_REGEXP
13221 struct RegExpInterruptionData {
13222 v8::base::Atomic32 loop_count;
13223 UC16VectorResource* string_resource;
13224 v8::Persistent<v8::String> string;
13225 } regexp_interruption_data;
13228 class RegExpInterruptionThread : public v8::base::Thread {
13230 explicit RegExpInterruptionThread(v8::Isolate* isolate)
13231 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
13233 virtual void Run() {
13234 for (v8::base::NoBarrier_Store(®exp_interruption_data.loop_count, 0);
13235 v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) < 7;
13236 v8::base::NoBarrier_AtomicIncrement(
13237 ®exp_interruption_data.loop_count, 1)) {
13238 v8::base::OS::Sleep(50); // Wait a bit before requesting GC.
13239 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
13241 v8::base::OS::Sleep(50); // Wait a bit before terminating.
13242 v8::V8::TerminateExecution(isolate_);
13246 v8::Isolate* isolate_;
13250 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
13251 if (v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) != 2) {
13254 v8::HandleScope scope(CcTest::isolate());
13255 v8::Local<v8::String> string = v8::Local<v8::String>::New(
13256 CcTest::isolate(), regexp_interruption_data.string);
13257 string->MakeExternal(regexp_interruption_data.string_resource);
13261 // Test that RegExp execution can be interrupted. Specifically, we test
13262 // * interrupting with GC
13263 // * turn the subject string from one-byte internal to two-byte external string
13264 // * force termination
13265 TEST(RegExpInterruption) {
13266 v8::HandleScope scope(CcTest::isolate());
13269 RegExpInterruptionThread timeout_thread(CcTest::isolate());
13271 v8::V8::AddGCPrologueCallback(RunBeforeGC);
13272 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
13273 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
13274 v8::Local<v8::String> string = v8_str(one_byte_content);
13276 CcTest::global()->Set(v8_str("a"), string);
13277 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
13278 regexp_interruption_data.string_resource = new UC16VectorResource(
13279 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
13281 v8::TryCatch try_catch;
13282 timeout_thread.Start();
13284 CompileRun("/((a*)*)*b/.exec(a)");
13285 CHECK(try_catch.HasTerminated());
13287 timeout_thread.Join();
13289 regexp_interruption_data.string.Reset();
13290 i::DeleteArray(uc16_content);
13293 #endif // V8_INTERPRETED_REGEXP
13296 // Test that we cannot set a property on the global object if there
13297 // is a read-only property in the prototype chain.
13298 TEST(ReadOnlyPropertyInGlobalProto) {
13299 v8::Isolate* isolate = CcTest::isolate();
13300 v8::HandleScope scope(isolate);
13301 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13302 LocalContext context(0, templ);
13303 v8::Handle<v8::Object> global = context->Global();
13304 v8::Handle<v8::Object> global_proto =
13305 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
13306 global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
13308 global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
13310 // Check without 'eval' or 'with'.
13311 v8::Handle<v8::Value> res =
13312 CompileRun("function f() { x = 42; return x; }; f()");
13313 CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13314 // Check with 'eval'.
13315 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
13316 CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13317 // Check with 'with'.
13318 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
13319 CHECK(v8::Integer::New(isolate, 0)->Equals(res));
13322 static int force_set_set_count = 0;
13323 static int force_set_get_count = 0;
13324 bool pass_on_get = false;
13326 static void ForceSetGetter(v8::Local<v8::String> name,
13327 const v8::PropertyCallbackInfo<v8::Value>& info) {
13328 force_set_get_count++;
13332 info.GetReturnValue().Set(3);
13335 static void ForceSetSetter(v8::Local<v8::String> name,
13336 v8::Local<v8::Value> value,
13337 const v8::PropertyCallbackInfo<void>& info) {
13338 force_set_set_count++;
13341 static void ForceSetInterceptGetter(
13342 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13343 CHECK(name->IsString());
13344 ForceSetGetter(Local<String>::Cast(name), info);
13347 static void ForceSetInterceptSetter(
13348 v8::Local<v8::Name> name, v8::Local<v8::Value> value,
13349 const v8::PropertyCallbackInfo<v8::Value>& info) {
13350 force_set_set_count++;
13351 info.GetReturnValue().SetUndefined();
13356 force_set_get_count = 0;
13357 force_set_set_count = 0;
13358 pass_on_get = false;
13360 v8::Isolate* isolate = CcTest::isolate();
13361 v8::HandleScope scope(isolate);
13362 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13363 v8::Handle<v8::String> access_property =
13364 v8::String::NewFromUtf8(isolate, "a");
13365 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
13366 LocalContext context(NULL, templ);
13367 v8::Handle<v8::Object> global = context->Global();
13369 // Ordinary properties
13370 v8::Handle<v8::String> simple_property =
13371 v8::String::NewFromUtf8(isolate, "p");
13372 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
13373 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13374 // This should fail because the property is read-only
13375 global->Set(simple_property, v8::Int32::New(isolate, 5));
13376 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
13377 // This should succeed even though the property is read-only
13378 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
13379 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
13382 CHECK_EQ(0, force_set_set_count);
13383 CHECK_EQ(0, force_set_get_count);
13384 CHECK_EQ(3, global->Get(access_property)->Int32Value());
13385 // CHECK_EQ the property shouldn't override it, just call the setter
13386 // which in this case does nothing.
13387 global->Set(access_property, v8::Int32::New(isolate, 7));
13388 CHECK_EQ(3, global->Get(access_property)->Int32Value());
13389 CHECK_EQ(1, force_set_set_count);
13390 CHECK_EQ(2, force_set_get_count);
13391 // Forcing the property to be set should override the accessor without
13393 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
13394 CHECK_EQ(8, global->Get(access_property)->Int32Value());
13395 CHECK_EQ(1, force_set_set_count);
13396 CHECK_EQ(2, force_set_get_count);
13400 TEST(ForceSetWithInterceptor) {
13401 force_set_get_count = 0;
13402 force_set_set_count = 0;
13403 pass_on_get = false;
13405 v8::Isolate* isolate = CcTest::isolate();
13406 v8::HandleScope scope(isolate);
13407 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
13408 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13409 ForceSetInterceptGetter, ForceSetInterceptSetter));
13410 LocalContext context(NULL, templ);
13411 v8::Handle<v8::Object> global = context->Global();
13413 v8::Handle<v8::String> some_property =
13414 v8::String::NewFromUtf8(isolate, "a");
13415 CHECK_EQ(0, force_set_set_count);
13416 CHECK_EQ(0, force_set_get_count);
13417 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13418 // Setting the property shouldn't override it, just call the setter
13419 // which in this case does nothing.
13420 global->Set(some_property, v8::Int32::New(isolate, 7));
13421 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13422 CHECK_EQ(1, force_set_set_count);
13423 CHECK_EQ(2, force_set_get_count);
13424 // Getting the property when the interceptor returns an empty handle
13425 // should yield undefined, since the property isn't present on the
13426 // object itself yet.
13427 pass_on_get = true;
13428 CHECK(global->Get(some_property)->IsUndefined());
13429 CHECK_EQ(1, force_set_set_count);
13430 CHECK_EQ(3, force_set_get_count);
13431 // Forcing the property to be set should cause the value to be
13432 // set locally without calling the interceptor.
13433 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
13434 CHECK_EQ(8, global->Get(some_property)->Int32Value());
13435 CHECK_EQ(1, force_set_set_count);
13436 CHECK_EQ(4, force_set_get_count);
13437 // Reenabling the interceptor should cause it to take precedence over
13439 pass_on_get = false;
13440 CHECK_EQ(3, global->Get(some_property)->Int32Value());
13441 CHECK_EQ(1, force_set_set_count);
13442 CHECK_EQ(5, force_set_get_count);
13443 // The interceptor should also work for other properties
13444 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
13446 CHECK_EQ(1, force_set_set_count);
13447 CHECK_EQ(6, force_set_get_count);
13451 static v8::Local<Context> calling_context0;
13452 static v8::Local<Context> calling_context1;
13453 static v8::Local<Context> calling_context2;
13456 // Check that the call to the callback is initiated in
13457 // calling_context2, the directly calling context is calling_context1
13458 // and the callback itself is in calling_context0.
13459 static void GetCallingContextCallback(
13460 const v8::FunctionCallbackInfo<v8::Value>& args) {
13461 ApiTestFuzzer::Fuzz();
13462 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
13463 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
13464 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
13465 args.GetReturnValue().Set(42);
13469 THREADED_TEST(GetCurrentContextWhenNotInContext) {
13470 i::Isolate* isolate = CcTest::i_isolate();
13471 CHECK(isolate != NULL);
13472 CHECK(isolate->context() == NULL);
13473 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
13474 v8::HandleScope scope(v8_isolate);
13475 // The following should not crash, but return an empty handle.
13476 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
13477 CHECK(current.IsEmpty());
13481 THREADED_TEST(GetCallingContext) {
13482 v8::Isolate* isolate = CcTest::isolate();
13483 v8::HandleScope scope(isolate);
13485 Local<Context> calling_context0(Context::New(isolate));
13486 Local<Context> calling_context1(Context::New(isolate));
13487 Local<Context> calling_context2(Context::New(isolate));
13488 ::calling_context0 = calling_context0;
13489 ::calling_context1 = calling_context1;
13490 ::calling_context2 = calling_context2;
13492 // Allow cross-domain access.
13493 Local<String> token = v8_str("<security token>");
13494 calling_context0->SetSecurityToken(token);
13495 calling_context1->SetSecurityToken(token);
13496 calling_context2->SetSecurityToken(token);
13498 // Create an object with a C++ callback in context0.
13499 calling_context0->Enter();
13500 Local<v8::FunctionTemplate> callback_templ =
13501 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
13502 calling_context0->Global()->Set(v8_str("callback"),
13503 callback_templ->GetFunction());
13504 calling_context0->Exit();
13506 // Expose context0 in context1 and set up a function that calls the
13507 // callback function.
13508 calling_context1->Enter();
13509 calling_context1->Global()->Set(v8_str("context0"),
13510 calling_context0->Global());
13511 CompileRun("function f() { context0.callback() }");
13512 calling_context1->Exit();
13514 // Expose context1 in context2 and call the callback function in
13515 // context0 indirectly through f in context1.
13516 calling_context2->Enter();
13517 calling_context2->Global()->Set(v8_str("context1"),
13518 calling_context1->Global());
13519 CompileRun("context1.f()");
13520 calling_context2->Exit();
13521 ::calling_context0.Clear();
13522 ::calling_context1.Clear();
13523 ::calling_context2.Clear();
13527 // Check that a variable declaration with no explicit initialization
13528 // value does shadow an existing property in the prototype chain.
13529 THREADED_TEST(InitGlobalVarInProtoChain) {
13530 LocalContext context;
13531 v8::HandleScope scope(context->GetIsolate());
13532 // Introduce a variable in the prototype chain.
13533 CompileRun("__proto__.x = 42");
13534 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
13535 CHECK(!result->IsUndefined());
13536 CHECK_EQ(43, result->Int32Value());
13540 // Regression test for issue 398.
13541 // If a function is added to an object, creating a constant function
13542 // field, and the result is cloned, replacing the constant function on the
13543 // original should not affect the clone.
13544 // See http://code.google.com/p/v8/issues/detail?id=398
13545 THREADED_TEST(ReplaceConstantFunction) {
13546 LocalContext context;
13547 v8::Isolate* isolate = context->GetIsolate();
13548 v8::HandleScope scope(isolate);
13549 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
13550 v8::Handle<v8::FunctionTemplate> func_templ =
13551 v8::FunctionTemplate::New(isolate);
13552 v8::Handle<v8::String> foo_string =
13553 v8::String::NewFromUtf8(isolate, "foo");
13554 obj->Set(foo_string, func_templ->GetFunction());
13555 v8::Handle<v8::Object> obj_clone = obj->Clone();
13556 obj_clone->Set(foo_string,
13557 v8::String::NewFromUtf8(isolate, "Hello"));
13558 CHECK(!obj->Get(foo_string)->IsUndefined());
13562 static void CheckElementValue(i::Isolate* isolate,
13564 i::Handle<i::Object> obj,
13566 i::Object* element =
13567 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
13568 CHECK_EQ(expected, i::Smi::cast(element)->value());
13572 THREADED_TEST(PixelArray) {
13573 LocalContext context;
13574 i::Isolate* isolate = CcTest::i_isolate();
13575 i::Factory* factory = isolate->factory();
13576 v8::HandleScope scope(context->GetIsolate());
13577 const int kElementCount = 260;
13578 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
13579 i::Handle<i::ExternalUint8ClampedArray> pixels =
13580 i::Handle<i::ExternalUint8ClampedArray>::cast(
13581 factory->NewExternalArray(kElementCount,
13582 v8::kExternalUint8ClampedArray,
13584 // Force GC to trigger verification.
13585 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13586 for (int i = 0; i < kElementCount; i++) {
13587 pixels->set(i, i % 256);
13589 // Force GC to trigger verification.
13590 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
13591 for (int i = 0; i < kElementCount; i++) {
13592 CHECK_EQ(i % 256, pixels->get_scalar(i));
13593 CHECK_EQ(i % 256, pixel_data[i]);
13596 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
13597 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
13598 // Set the elements to be the pixels.
13599 // jsobj->set_elements(*pixels);
13600 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
13601 CheckElementValue(isolate, 1, jsobj, 1);
13602 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
13603 context->Global()->Set(v8_str("pixels"), obj);
13604 v8::Handle<v8::Value> result = CompileRun("pixels.field");
13605 CHECK_EQ(1503, result->Int32Value());
13606 result = CompileRun("pixels[1]");
13607 CHECK_EQ(1, result->Int32Value());
13609 result = CompileRun("var sum = 0;"
13610 "for (var i = 0; i < 8; i++) {"
13611 " sum += pixels[i] = pixels[i] = -i;"
13614 CHECK_EQ(-28, result->Int32Value());
13616 result = CompileRun("var sum = 0;"
13617 "for (var i = 0; i < 8; i++) {"
13618 " sum += pixels[i] = pixels[i] = 0;"
13621 CHECK_EQ(0, result->Int32Value());
13623 result = CompileRun("var sum = 0;"
13624 "for (var i = 0; i < 8; i++) {"
13625 " sum += pixels[i] = pixels[i] = 255;"
13628 CHECK_EQ(8 * 255, result->Int32Value());
13630 result = CompileRun("var sum = 0;"
13631 "for (var i = 0; i < 8; i++) {"
13632 " sum += pixels[i] = pixels[i] = 256 + i;"
13635 CHECK_EQ(2076, result->Int32Value());
13637 result = CompileRun("var sum = 0;"
13638 "for (var i = 0; i < 8; i++) {"
13639 " sum += pixels[i] = pixels[i] = i;"
13642 CHECK_EQ(28, result->Int32Value());
13644 result = CompileRun("var sum = 0;"
13645 "for (var i = 0; i < 8; i++) {"
13646 " sum += pixels[i];"
13649 CHECK_EQ(28, result->Int32Value());
13651 i::Handle<i::Smi> value(i::Smi::FromInt(2),
13652 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
13653 i::Handle<i::Object> no_failure;
13654 no_failure = i::JSObject::SetElement(
13655 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
13656 DCHECK(!no_failure.is_null());
13658 CheckElementValue(isolate, 2, jsobj, 1);
13659 *value.location() = i::Smi::FromInt(256);
13660 no_failure = i::JSObject::SetElement(
13661 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
13662 DCHECK(!no_failure.is_null());
13664 CheckElementValue(isolate, 255, jsobj, 1);
13665 *value.location() = i::Smi::FromInt(-1);
13666 no_failure = i::JSObject::SetElement(
13667 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
13668 DCHECK(!no_failure.is_null());
13670 CheckElementValue(isolate, 0, jsobj, 1);
13672 result = CompileRun("for (var i = 0; i < 8; i++) {"
13673 " pixels[i] = (i * 65) - 109;"
13675 "pixels[1] + pixels[6];");
13676 CHECK_EQ(255, result->Int32Value());
13677 CheckElementValue(isolate, 0, jsobj, 0);
13678 CheckElementValue(isolate, 0, jsobj, 1);
13679 CheckElementValue(isolate, 21, jsobj, 2);
13680 CheckElementValue(isolate, 86, jsobj, 3);
13681 CheckElementValue(isolate, 151, jsobj, 4);
13682 CheckElementValue(isolate, 216, jsobj, 5);
13683 CheckElementValue(isolate, 255, jsobj, 6);
13684 CheckElementValue(isolate, 255, jsobj, 7);
13685 result = CompileRun("var sum = 0;"
13686 "for (var i = 0; i < 8; i++) {"
13687 " sum += pixels[i];"
13690 CHECK_EQ(984, result->Int32Value());
13692 result = CompileRun("for (var i = 0; i < 8; i++) {"
13693 " pixels[i] = (i * 1.1);"
13695 "pixels[1] + pixels[6];");
13696 CHECK_EQ(8, result->Int32Value());
13697 CheckElementValue(isolate, 0, jsobj, 0);
13698 CheckElementValue(isolate, 1, jsobj, 1);
13699 CheckElementValue(isolate, 2, jsobj, 2);
13700 CheckElementValue(isolate, 3, jsobj, 3);
13701 CheckElementValue(isolate, 4, jsobj, 4);
13702 CheckElementValue(isolate, 6, jsobj, 5);
13703 CheckElementValue(isolate, 7, jsobj, 6);
13704 CheckElementValue(isolate, 8, jsobj, 7);
13706 result = CompileRun("for (var i = 0; i < 8; i++) {"
13707 " pixels[7] = undefined;"
13710 CHECK_EQ(0, result->Int32Value());
13711 CheckElementValue(isolate, 0, jsobj, 7);
13713 result = CompileRun("for (var i = 0; i < 8; i++) {"
13714 " pixels[6] = '2.3';"
13717 CHECK_EQ(2, result->Int32Value());
13718 CheckElementValue(isolate, 2, jsobj, 6);
13720 result = CompileRun("for (var i = 0; i < 8; i++) {"
13721 " pixels[5] = NaN;"
13724 CHECK_EQ(0, result->Int32Value());
13725 CheckElementValue(isolate, 0, jsobj, 5);
13727 result = CompileRun("for (var i = 0; i < 8; i++) {"
13728 " pixels[8] = Infinity;"
13731 CHECK_EQ(255, result->Int32Value());
13732 CheckElementValue(isolate, 255, jsobj, 8);
13734 result = CompileRun("for (var i = 0; i < 8; i++) {"
13735 " pixels[9] = -Infinity;"
13738 CHECK_EQ(0, result->Int32Value());
13739 CheckElementValue(isolate, 0, jsobj, 9);
13741 result = CompileRun("pixels[3] = 33;"
13742 "delete pixels[3];"
13744 CHECK_EQ(33, result->Int32Value());
13746 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
13747 "pixels[2] = 12; pixels[3] = 13;"
13748 "pixels.__defineGetter__('2',"
13749 "function() { return 120; });"
13751 CHECK_EQ(12, result->Int32Value());
13753 result = CompileRun("var js_array = new Array(40);"
13754 "js_array[0] = 77;"
13756 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13758 result = CompileRun("pixels[1] = 23;"
13759 "pixels.__proto__ = [];"
13760 "js_array.__proto__ = pixels;"
13761 "js_array.concat(pixels);");
13762 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
13763 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
13765 result = CompileRun("pixels[1] = 23;");
13766 CHECK_EQ(23, result->Int32Value());
13768 // Test for index greater than 255. Regression test for:
13769 // http://code.google.com/p/chromium/issues/detail?id=26337.
13770 result = CompileRun("pixels[256] = 255;");
13771 CHECK_EQ(255, result->Int32Value());
13772 result = CompileRun("var i = 0;"
13773 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
13775 CHECK_EQ(255, result->Int32Value());
13777 // Make sure that pixel array ICs recognize when a non-pixel array
13778 // is passed to it.
13779 result = CompileRun("function pa_load(p) {"
13781 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13784 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13785 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13786 "just_ints = new Object();"
13787 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13788 "for (var i = 0; i < 10; ++i) {"
13789 " result = pa_load(just_ints);"
13792 CHECK_EQ(32640, result->Int32Value());
13794 // Make sure that pixel array ICs recognize out-of-bound accesses.
13795 result = CompileRun("function pa_load(p, start) {"
13797 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13800 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13801 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13802 "for (var i = 0; i < 10; ++i) {"
13803 " result = pa_load(pixels,-10);"
13806 CHECK_EQ(0, result->Int32Value());
13808 // Make sure that generic ICs properly handles a pixel array.
13809 result = CompileRun("function pa_load(p) {"
13811 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13814 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13815 "just_ints = new Object();"
13816 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13817 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13818 "for (var i = 0; i < 10; ++i) {"
13819 " result = pa_load(pixels);"
13822 CHECK_EQ(32640, result->Int32Value());
13824 // Make sure that generic load ICs recognize out-of-bound accesses in
13826 result = CompileRun("function pa_load(p, start) {"
13828 " for (var j = start; j < 256; j++) { sum += p[j]; }"
13831 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13832 "just_ints = new Object();"
13833 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13834 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
13835 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
13836 "for (var i = 0; i < 10; ++i) {"
13837 " result = pa_load(pixels,-10);"
13840 CHECK_EQ(0, result->Int32Value());
13842 // Make sure that generic ICs properly handles other types than pixel
13843 // arrays (that the inlined fast pixel array test leaves the right information
13844 // in the right registers).
13845 result = CompileRun("function pa_load(p) {"
13847 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
13850 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13851 "just_ints = new Object();"
13852 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13853 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
13854 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
13855 "sparse_array = new Object();"
13856 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
13857 "sparse_array[1000000] = 3;"
13858 "for (var i = 0; i < 10; ++i) {"
13859 " result = pa_load(sparse_array);"
13862 CHECK_EQ(32640, result->Int32Value());
13864 // Make sure that pixel array store ICs clamp values correctly.
13865 result = CompileRun("function pa_store(p) {"
13866 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13868 "pa_store(pixels);"
13870 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13872 CHECK_EQ(48896, result->Int32Value());
13874 // Make sure that pixel array stores correctly handle accesses outside
13875 // of the pixel array..
13876 result = CompileRun("function pa_store(p,start) {"
13877 " for (var j = 0; j < 256; j++) {"
13878 " p[j+start] = j * 2;"
13881 "pa_store(pixels,0);"
13882 "pa_store(pixels,-128);"
13884 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13886 CHECK_EQ(65280, result->Int32Value());
13888 // Make sure that the generic store stub correctly handle accesses outside
13889 // of the pixel array..
13890 result = CompileRun("function pa_store(p,start) {"
13891 " for (var j = 0; j < 256; j++) {"
13892 " p[j+start] = j * 2;"
13895 "pa_store(pixels,0);"
13896 "just_ints = new Object();"
13897 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
13898 "pa_store(just_ints, 0);"
13899 "pa_store(pixels,-128);"
13901 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13903 CHECK_EQ(65280, result->Int32Value());
13905 // Make sure that the generic keyed store stub clamps pixel array values
13907 result = CompileRun("function pa_store(p) {"
13908 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
13910 "pa_store(pixels);"
13911 "just_ints = new Object();"
13912 "pa_store(just_ints);"
13913 "pa_store(pixels);"
13915 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
13917 CHECK_EQ(48896, result->Int32Value());
13919 // Make sure that pixel array loads are optimized by crankshaft.
13920 result = CompileRun("function pa_load(p) {"
13922 " for (var i=0; i<256; ++i) {"
13927 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
13928 "for (var i = 0; i < 5000; ++i) {"
13929 " result = pa_load(pixels);"
13932 CHECK_EQ(32640, result->Int32Value());
13934 // Make sure that pixel array stores are optimized by crankshaft.
13935 result = CompileRun("function pa_init(p) {"
13936 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
13938 "function pa_load(p) {"
13940 " for (var i=0; i<256; ++i) {"
13945 "for (var i = 0; i < 5000; ++i) {"
13946 " pa_init(pixels);"
13948 "result = pa_load(pixels);"
13950 CHECK_EQ(32640, result->Int32Value());
13956 THREADED_TEST(PixelArrayInfo) {
13957 LocalContext context;
13958 v8::HandleScope scope(context->GetIsolate());
13959 for (int size = 0; size < 100; size += 10) {
13960 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
13961 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
13962 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
13963 CHECK(obj->HasIndexedPropertiesInPixelData());
13964 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
13965 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
13971 static void NotHandledIndexedPropertyGetter(
13973 const v8::PropertyCallbackInfo<v8::Value>& info) {
13974 ApiTestFuzzer::Fuzz();
13978 static void NotHandledIndexedPropertySetter(
13980 Local<Value> value,
13981 const v8::PropertyCallbackInfo<v8::Value>& info) {
13982 ApiTestFuzzer::Fuzz();
13986 THREADED_TEST(PixelArrayWithInterceptor) {
13987 LocalContext context;
13988 i::Factory* factory = CcTest::i_isolate()->factory();
13989 v8::Isolate* isolate = context->GetIsolate();
13990 v8::HandleScope scope(isolate);
13991 const int kElementCount = 260;
13992 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
13993 i::Handle<i::ExternalUint8ClampedArray> pixels =
13994 i::Handle<i::ExternalUint8ClampedArray>::cast(
13995 factory->NewExternalArray(kElementCount,
13996 v8::kExternalUint8ClampedArray,
13998 for (int i = 0; i < kElementCount; i++) {
13999 pixels->set(i, i % 256);
14001 v8::Handle<v8::ObjectTemplate> templ =
14002 v8::ObjectTemplate::New(context->GetIsolate());
14003 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
14004 NotHandledIndexedPropertyGetter, NotHandledIndexedPropertySetter));
14005 v8::Handle<v8::Object> obj = templ->NewInstance();
14006 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
14007 context->Global()->Set(v8_str("pixels"), obj);
14008 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
14009 CHECK_EQ(1, result->Int32Value());
14010 result = CompileRun("var sum = 0;"
14011 "for (var i = 0; i < 8; i++) {"
14012 " sum += pixels[i] = pixels[i] = -i;"
14015 CHECK_EQ(-28, result->Int32Value());
14016 result = CompileRun("pixels.hasOwnProperty('1')");
14017 CHECK(result->BooleanValue());
14022 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
14023 switch (array_type) {
14024 case v8::kExternalInt8Array:
14025 case v8::kExternalUint8Array:
14026 case v8::kExternalUint8ClampedArray:
14029 case v8::kExternalInt16Array:
14030 case v8::kExternalUint16Array:
14033 case v8::kExternalInt32Array:
14034 case v8::kExternalUint32Array:
14035 case v8::kExternalFloat32Array:
14038 case v8::kExternalFloat64Array:
14050 template <class ExternalArrayClass, class ElementType>
14051 static void ObjectWithExternalArrayTestHelper(
14052 Handle<Context> context,
14053 v8::Handle<Object> obj,
14055 v8::ExternalArrayType array_type,
14056 int64_t low, int64_t high) {
14057 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14058 i::Isolate* isolate = jsobj->GetIsolate();
14059 obj->Set(v8_str("field"),
14060 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
14061 context->Global()->Set(v8_str("ext_array"), obj);
14062 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
14063 CHECK_EQ(1503, result->Int32Value());
14064 result = CompileRun("ext_array[1]");
14065 CHECK_EQ(1, result->Int32Value());
14067 // Check assigned smis
14068 result = CompileRun("for (var i = 0; i < 8; i++) {"
14069 " ext_array[i] = i;"
14072 "for (var i = 0; i < 8; i++) {"
14073 " sum += ext_array[i];"
14077 CHECK_EQ(28, result->Int32Value());
14078 // Check pass through of assigned smis
14079 result = CompileRun("var sum = 0;"
14080 "for (var i = 0; i < 8; i++) {"
14081 " sum += ext_array[i] = ext_array[i] = -i;"
14084 CHECK_EQ(-28, result->Int32Value());
14087 // Check assigned smis in reverse order
14088 result = CompileRun("for (var i = 8; --i >= 0; ) {"
14089 " ext_array[i] = i;"
14092 "for (var i = 0; i < 8; i++) {"
14093 " sum += ext_array[i];"
14096 CHECK_EQ(28, result->Int32Value());
14098 // Check pass through of assigned HeapNumbers
14099 result = CompileRun("var sum = 0;"
14100 "for (var i = 0; i < 16; i+=2) {"
14101 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
14104 CHECK_EQ(-28, result->Int32Value());
14106 // Check assigned HeapNumbers
14107 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
14108 " ext_array[i] = (i * 0.5);"
14111 "for (var i = 0; i < 16; i+=2) {"
14112 " sum += ext_array[i];"
14115 CHECK_EQ(28, result->Int32Value());
14117 // Check assigned HeapNumbers in reverse order
14118 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
14119 " ext_array[i] = (i * 0.5);"
14122 "for (var i = 0; i < 16; i+=2) {"
14123 " sum += ext_array[i];"
14126 CHECK_EQ(28, result->Int32Value());
14128 i::ScopedVector<char> test_buf(1024);
14130 // Check legal boundary conditions.
14131 // The repeated loads and stores ensure the ICs are exercised.
14132 const char* boundary_program =
14134 "for (var i = 0; i < 16; i++) {"
14135 " ext_array[i] = %lld;"
14137 " res = ext_array[i];"
14141 i::SNPrintF(test_buf,
14144 result = CompileRun(test_buf.start());
14145 CHECK_EQ(low, result->IntegerValue());
14147 i::SNPrintF(test_buf,
14150 result = CompileRun(test_buf.start());
14151 CHECK_EQ(high, result->IntegerValue());
14153 // Check misprediction of type in IC.
14154 result = CompileRun("var tmp_array = ext_array;"
14156 "for (var i = 0; i < 8; i++) {"
14157 " tmp_array[i] = i;"
14158 " sum += tmp_array[i];"
14164 // Force GC to trigger verification.
14165 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14166 CHECK_EQ(28, result->Int32Value());
14168 // Make sure out-of-range loads do not throw.
14169 i::SNPrintF(test_buf,
14170 "var caught_exception = false;"
14174 " caught_exception = true;"
14176 "caught_exception;",
14178 result = CompileRun(test_buf.start());
14179 CHECK_EQ(false, result->BooleanValue());
14181 // Make sure out-of-range stores do not throw.
14182 i::SNPrintF(test_buf,
14183 "var caught_exception = false;"
14185 " ext_array[%d] = 1;"
14187 " caught_exception = true;"
14189 "caught_exception;",
14191 result = CompileRun(test_buf.start());
14192 CHECK_EQ(false, result->BooleanValue());
14194 // Check other boundary conditions, values and operations.
14195 result = CompileRun("for (var i = 0; i < 8; i++) {"
14196 " ext_array[7] = undefined;"
14199 CHECK_EQ(0, result->Int32Value());
14200 if (array_type == v8::kExternalFloat64Array ||
14201 array_type == v8::kExternalFloat32Array) {
14203 i::Object::GetElement(isolate, jsobj, 7).ToHandleChecked()->Number()));
14205 CheckElementValue(isolate, 0, jsobj, 7);
14208 result = CompileRun("for (var i = 0; i < 8; i++) {"
14209 " ext_array[6] = '2.3';"
14212 CHECK_EQ(2, result->Int32Value());
14215 i::Object::GetElement(
14216 isolate, jsobj, 6).ToHandleChecked()->Number()));
14218 if (array_type != v8::kExternalFloat32Array &&
14219 array_type != v8::kExternalFloat64Array) {
14220 // Though the specification doesn't state it, be explicit about
14221 // converting NaNs and +/-Infinity to zero.
14222 result = CompileRun("for (var i = 0; i < 8; i++) {"
14223 " ext_array[i] = 5;"
14225 "for (var i = 0; i < 8; i++) {"
14226 " ext_array[i] = NaN;"
14229 CHECK_EQ(0, result->Int32Value());
14230 CheckElementValue(isolate, 0, jsobj, 5);
14232 result = CompileRun("for (var i = 0; i < 8; i++) {"
14233 " ext_array[i] = 5;"
14235 "for (var i = 0; i < 8; i++) {"
14236 " ext_array[i] = Infinity;"
14239 int expected_value =
14240 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
14241 CHECK_EQ(expected_value, result->Int32Value());
14242 CheckElementValue(isolate, expected_value, jsobj, 5);
14244 result = CompileRun("for (var i = 0; i < 8; i++) {"
14245 " ext_array[i] = 5;"
14247 "for (var i = 0; i < 8; i++) {"
14248 " ext_array[i] = -Infinity;"
14251 CHECK_EQ(0, result->Int32Value());
14252 CheckElementValue(isolate, 0, jsobj, 5);
14254 // Check truncation behavior of integral arrays.
14255 const char* unsigned_data =
14256 "var source_data = [0.6, 10.6];"
14257 "var expected_results = [0, 10];";
14258 const char* signed_data =
14259 "var source_data = [0.6, 10.6, -0.6, -10.6];"
14260 "var expected_results = [0, 10, 0, -10];";
14261 const char* pixel_data =
14262 "var source_data = [0.6, 10.6];"
14263 "var expected_results = [1, 11];";
14265 (array_type == v8::kExternalUint8Array ||
14266 array_type == v8::kExternalUint16Array ||
14267 array_type == v8::kExternalUint32Array);
14268 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
14270 i::SNPrintF(test_buf,
14272 "var all_passed = true;"
14273 "for (var i = 0; i < source_data.length; i++) {"
14274 " for (var j = 0; j < 8; j++) {"
14275 " ext_array[j] = source_data[i];"
14277 " all_passed = all_passed &&"
14278 " (ext_array[5] == expected_results[i]);"
14283 (is_pixel_data ? pixel_data : signed_data)));
14284 result = CompileRun(test_buf.start());
14285 CHECK_EQ(true, result->BooleanValue());
14288 i::Handle<ExternalArrayClass> array(
14289 ExternalArrayClass::cast(jsobj->elements()));
14290 for (int i = 0; i < element_count; i++) {
14291 array->set(i, static_cast<ElementType>(i));
14294 // Test complex assignments
14295 result = CompileRun("function ee_op_test_complex_func(sum) {"
14296 " for (var i = 0; i < 40; ++i) {"
14297 " sum += (ext_array[i] += 1);"
14298 " sum += (ext_array[i] -= 1);"
14303 "for (var i=0;i<10000;++i) {"
14304 " sum=ee_op_test_complex_func(sum);"
14307 CHECK_EQ(16000000, result->Int32Value());
14309 // Test count operations
14310 result = CompileRun("function ee_op_test_count_func(sum) {"
14311 " for (var i = 0; i < 40; ++i) {"
14312 " sum += (++ext_array[i]);"
14313 " sum += (--ext_array[i]);"
14318 "for (var i=0;i<10000;++i) {"
14319 " sum=ee_op_test_count_func(sum);"
14322 CHECK_EQ(16000000, result->Int32Value());
14324 result = CompileRun("ext_array[3] = 33;"
14325 "delete ext_array[3];"
14327 CHECK_EQ(33, result->Int32Value());
14329 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
14330 "ext_array[2] = 12; ext_array[3] = 13;"
14331 "ext_array.__defineGetter__('2',"
14332 "function() { return 120; });"
14334 CHECK_EQ(12, result->Int32Value());
14336 result = CompileRun("var js_array = new Array(40);"
14337 "js_array[0] = 77;"
14339 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14341 result = CompileRun("ext_array[1] = 23;"
14342 "ext_array.__proto__ = [];"
14343 "js_array.__proto__ = ext_array;"
14344 "js_array.concat(ext_array);");
14345 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
14346 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
14348 result = CompileRun("ext_array[1] = 23;");
14349 CHECK_EQ(23, result->Int32Value());
14353 template <class FixedTypedArrayClass,
14354 i::ElementsKind elements_kind,
14356 static void FixedTypedArrayTestHelper(
14357 v8::ExternalArrayType array_type,
14359 ElementType high) {
14360 i::FLAG_allow_natives_syntax = true;
14361 LocalContext context;
14362 i::Isolate* isolate = CcTest::i_isolate();
14363 i::Factory* factory = isolate->factory();
14364 v8::HandleScope scope(context->GetIsolate());
14365 const int kElementCount = 260;
14366 i::Handle<FixedTypedArrayClass> fixed_array =
14367 i::Handle<FixedTypedArrayClass>::cast(
14368 factory->NewFixedTypedArray(kElementCount, array_type));
14369 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
14370 fixed_array->map()->instance_type());
14371 CHECK_EQ(kElementCount, fixed_array->length());
14372 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14373 for (int i = 0; i < kElementCount; i++) {
14374 fixed_array->set(i, static_cast<ElementType>(i));
14376 // Force GC to trigger verification.
14377 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14378 for (int i = 0; i < kElementCount; i++) {
14379 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
14380 static_cast<int64_t>(fixed_array->get_scalar(i)));
14382 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
14383 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14384 i::Handle<i::Map> fixed_array_map =
14385 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
14386 jsobj->set_map(*fixed_array_map);
14387 jsobj->set_elements(*fixed_array);
14389 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
14390 context.local(), obj, kElementCount, array_type,
14391 static_cast<int64_t>(low),
14392 static_cast<int64_t>(high));
14396 THREADED_TEST(FixedUint8Array) {
14397 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
14398 v8::kExternalUint8Array,
14403 THREADED_TEST(FixedUint8ClampedArray) {
14404 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
14405 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
14406 v8::kExternalUint8ClampedArray,
14411 THREADED_TEST(FixedInt8Array) {
14412 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
14413 v8::kExternalInt8Array,
14418 THREADED_TEST(FixedUint16Array) {
14419 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
14420 v8::kExternalUint16Array,
14425 THREADED_TEST(FixedInt16Array) {
14426 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
14427 v8::kExternalInt16Array,
14432 THREADED_TEST(FixedUint32Array) {
14433 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
14434 v8::kExternalUint32Array,
14439 THREADED_TEST(FixedInt32Array) {
14440 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
14441 v8::kExternalInt32Array,
14446 THREADED_TEST(FixedFloat32Array) {
14447 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
14448 v8::kExternalFloat32Array,
14453 THREADED_TEST(FixedFloat64Array) {
14454 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
14455 v8::kExternalFloat64Array,
14460 template <class ExternalArrayClass, class ElementType>
14461 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
14464 LocalContext context;
14465 i::Isolate* isolate = CcTest::i_isolate();
14466 i::Factory* factory = isolate->factory();
14467 v8::HandleScope scope(context->GetIsolate());
14468 const int kElementCount = 40;
14469 int element_size = ExternalArrayElementSize(array_type);
14470 ElementType* array_data =
14471 static_cast<ElementType*>(malloc(kElementCount * element_size));
14472 i::Handle<ExternalArrayClass> array =
14473 i::Handle<ExternalArrayClass>::cast(
14474 factory->NewExternalArray(kElementCount, array_type, array_data));
14475 // Force GC to trigger verification.
14476 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14477 for (int i = 0; i < kElementCount; i++) {
14478 array->set(i, static_cast<ElementType>(i));
14480 // Force GC to trigger verification.
14481 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14482 for (int i = 0; i < kElementCount; i++) {
14483 CHECK_EQ(static_cast<int64_t>(i),
14484 static_cast<int64_t>(array->get_scalar(i)));
14485 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
14488 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
14489 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
14490 // Set the elements to be the external array.
14491 obj->SetIndexedPropertiesToExternalArrayData(array_data,
14496 i::Object::GetElement(
14497 isolate, jsobj, 1).ToHandleChecked()->Number()));
14499 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
14500 context.local(), obj, kElementCount, array_type, low, high);
14502 v8::Handle<v8::Value> result;
14504 // Test more complex manipulations which cause eax to contain values
14505 // that won't be completely overwritten by loads from the arrays.
14506 // This catches bugs in the instructions used for the KeyedLoadIC
14507 // for byte and word types.
14509 const int kXSize = 300;
14510 const int kYSize = 300;
14511 const int kLargeElementCount = kXSize * kYSize * 4;
14512 ElementType* large_array_data =
14513 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
14514 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
14515 // Set the elements to be the external array.
14516 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
14518 kLargeElementCount);
14519 context->Global()->Set(v8_str("large_array"), large_obj);
14520 // Initialize contents of a few rows.
14521 for (int x = 0; x < 300; x++) {
14523 int offset = row * 300 * 4;
14524 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14525 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14526 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14527 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14529 offset = row * 300 * 4;
14530 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14531 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14532 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14533 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14535 offset = row * 300 * 4;
14536 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
14537 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
14538 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
14539 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
14541 // The goal of the code below is to make "offset" large enough
14542 // that the computation of the index (which goes into eax) has
14543 // high bits set which will not be overwritten by a byte or short
14545 result = CompileRun("var failed = false;"
14547 "for (var i = 0; i < 300; i++) {"
14548 " if (large_array[4 * i] != 127 ||"
14549 " large_array[4 * i + 1] != 0 ||"
14550 " large_array[4 * i + 2] != 0 ||"
14551 " large_array[4 * i + 3] != 127) {"
14555 "offset = 150 * 300 * 4;"
14556 "for (var i = 0; i < 300; i++) {"
14557 " if (large_array[offset + 4 * i] != 127 ||"
14558 " large_array[offset + 4 * i + 1] != 0 ||"
14559 " large_array[offset + 4 * i + 2] != 0 ||"
14560 " large_array[offset + 4 * i + 3] != 127) {"
14564 "offset = 298 * 300 * 4;"
14565 "for (var i = 0; i < 300; i++) {"
14566 " if (large_array[offset + 4 * i] != 127 ||"
14567 " large_array[offset + 4 * i + 1] != 0 ||"
14568 " large_array[offset + 4 * i + 2] != 0 ||"
14569 " large_array[offset + 4 * i + 3] != 127) {"
14574 CHECK_EQ(true, result->BooleanValue());
14575 free(large_array_data);
14578 // The "" property descriptor is overloaded to store information about
14579 // the external array. Ensure that setting and accessing the "" property
14580 // works (it should overwrite the information cached about the external
14581 // array in the DescriptorArray) in various situations.
14582 result = CompileRun("ext_array[''] = 23; ext_array['']");
14583 CHECK_EQ(23, result->Int32Value());
14585 // Property "" set after the external array is associated with the object.
14587 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14588 obj2->Set(v8_str("ee_test_field"),
14589 v8::Int32::New(context->GetIsolate(), 256));
14590 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
14591 // Set the elements to be the external array.
14592 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14595 context->Global()->Set(v8_str("ext_array"), obj2);
14596 result = CompileRun("ext_array['']");
14597 CHECK_EQ(1503, result->Int32Value());
14600 // Property "" set after the external array is associated with the object.
14602 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14603 obj2->Set(v8_str("ee_test_field_2"),
14604 v8::Int32::New(context->GetIsolate(), 256));
14605 // Set the elements to be the external array.
14606 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14609 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
14610 context->Global()->Set(v8_str("ext_array"), obj2);
14611 result = CompileRun("ext_array['']");
14612 CHECK_EQ(1503, result->Int32Value());
14615 // Should reuse the map from previous test.
14617 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14618 obj2->Set(v8_str("ee_test_field_2"),
14619 v8::Int32::New(context->GetIsolate(), 256));
14620 // Set the elements to be the external array. Should re-use the map
14621 // from previous test.
14622 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
14625 context->Global()->Set(v8_str("ext_array"), obj2);
14626 result = CompileRun("ext_array['']");
14629 // Property "" is a constant function that shouldn't not be interfered with
14630 // when an external array is set.
14632 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14634 obj2->Set(v8_str("ee_test_field3"),
14635 v8::Int32::New(context->GetIsolate(), 256));
14637 // Add a constant function to an object.
14638 context->Global()->Set(v8_str("ext_array"), obj2);
14639 result = CompileRun("ext_array[''] = function() {return 1503;};"
14640 "ext_array['']();");
14642 // Add an external array transition to the same map that
14643 // has the constant transition.
14644 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
14645 obj3->Set(v8_str("ee_test_field3"),
14646 v8::Int32::New(context->GetIsolate(), 256));
14647 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14650 context->Global()->Set(v8_str("ext_array"), obj3);
14653 // If a external array transition is in the map, it should get clobbered
14654 // by a constant function.
14656 // Add an external array transition.
14657 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
14658 obj3->Set(v8_str("ee_test_field4"),
14659 v8::Int32::New(context->GetIsolate(), 256));
14660 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
14664 // Add a constant function to the same map that just got an external array
14666 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
14667 obj2->Set(v8_str("ee_test_field4"),
14668 v8::Int32::New(context->GetIsolate(), 256));
14669 context->Global()->Set(v8_str("ext_array"), obj2);
14670 result = CompileRun("ext_array[''] = function() {return 1503;};"
14671 "ext_array['']();");
14678 THREADED_TEST(ExternalInt8Array) {
14679 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
14680 v8::kExternalInt8Array,
14686 THREADED_TEST(ExternalUint8Array) {
14687 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
14688 v8::kExternalUint8Array,
14694 THREADED_TEST(ExternalUint8ClampedArray) {
14695 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
14696 v8::kExternalUint8ClampedArray,
14702 THREADED_TEST(ExternalInt16Array) {
14703 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
14704 v8::kExternalInt16Array,
14710 THREADED_TEST(ExternalUint16Array) {
14711 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
14712 v8::kExternalUint16Array,
14718 THREADED_TEST(ExternalInt32Array) {
14719 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
14720 v8::kExternalInt32Array,
14721 INT_MIN, // -2147483648
14722 INT_MAX); // 2147483647
14726 THREADED_TEST(ExternalUint32Array) {
14727 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
14728 v8::kExternalUint32Array,
14730 UINT_MAX); // 4294967295
14734 THREADED_TEST(ExternalFloat32Array) {
14735 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
14736 v8::kExternalFloat32Array,
14742 THREADED_TEST(ExternalFloat64Array) {
14743 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
14744 v8::kExternalFloat64Array,
14750 THREADED_TEST(ExternalArrays) {
14751 TestExternalInt8Array();
14752 TestExternalUint8Array();
14753 TestExternalInt16Array();
14754 TestExternalUint16Array();
14755 TestExternalInt32Array();
14756 TestExternalUint32Array();
14757 TestExternalFloat32Array();
14761 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
14762 LocalContext context;
14763 v8::HandleScope scope(context->GetIsolate());
14764 for (int size = 0; size < 100; size += 10) {
14765 int element_size = ExternalArrayElementSize(array_type);
14766 void* external_data = malloc(size * element_size);
14767 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
14768 obj->SetIndexedPropertiesToExternalArrayData(
14769 external_data, array_type, size);
14770 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
14771 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
14772 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
14773 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
14774 free(external_data);
14779 THREADED_TEST(ExternalArrayInfo) {
14780 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
14781 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
14782 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
14783 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
14784 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
14785 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
14786 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
14787 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
14788 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
14792 void ExtArrayLimitsHelper(v8::Isolate* isolate,
14793 v8::ExternalArrayType array_type,
14795 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
14796 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
14797 last_location = last_message = NULL;
14798 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
14799 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
14800 CHECK(last_location);
14801 CHECK(last_message);
14805 TEST(ExternalArrayLimits) {
14806 LocalContext context;
14807 v8::Isolate* isolate = context->GetIsolate();
14808 v8::HandleScope scope(isolate);
14809 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
14810 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
14811 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
14812 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
14813 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
14814 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
14815 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
14816 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
14817 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
14818 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
14819 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
14820 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
14821 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
14822 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
14823 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
14824 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
14825 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
14826 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
14830 template <typename ElementType, typename TypedArray,
14831 class ExternalArrayClass>
14832 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
14833 int64_t low, int64_t high) {
14834 const int kElementCount = 50;
14836 i::ScopedVector<ElementType> backing_store(kElementCount+2);
14839 v8::Isolate* isolate = env->GetIsolate();
14840 v8::HandleScope handle_scope(isolate);
14842 Local<v8::ArrayBuffer> ab =
14843 v8::ArrayBuffer::New(isolate, backing_store.start(),
14844 (kElementCount + 2) * sizeof(ElementType));
14845 Local<TypedArray> ta =
14846 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
14847 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
14848 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
14849 CHECK_EQ(2 * sizeof(ElementType), ta->ByteOffset());
14850 CHECK_EQ(kElementCount * sizeof(ElementType), ta->ByteLength());
14851 CHECK(ab->Equals(ta->Buffer()));
14853 ElementType* data = backing_store.start() + 2;
14854 for (int i = 0; i < kElementCount; i++) {
14855 data[i] = static_cast<ElementType>(i);
14858 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
14859 env.local(), ta, kElementCount, array_type, low, high);
14863 THREADED_TEST(Uint8Array) {
14864 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
14865 v8::kExternalUint8Array, 0, 0xFF);
14869 THREADED_TEST(Int8Array) {
14870 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
14871 v8::kExternalInt8Array, -0x80, 0x7F);
14875 THREADED_TEST(Uint16Array) {
14876 TypedArrayTestHelper<uint16_t,
14878 i::ExternalUint16Array>(
14879 v8::kExternalUint16Array, 0, 0xFFFF);
14883 THREADED_TEST(Int16Array) {
14884 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
14885 v8::kExternalInt16Array, -0x8000, 0x7FFF);
14889 THREADED_TEST(Uint32Array) {
14890 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
14891 v8::kExternalUint32Array, 0, UINT_MAX);
14895 THREADED_TEST(Int32Array) {
14896 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
14897 v8::kExternalInt32Array, INT_MIN, INT_MAX);
14901 THREADED_TEST(Float32Array) {
14902 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
14903 v8::kExternalFloat32Array, -500, 500);
14907 THREADED_TEST(Float64Array) {
14908 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
14909 v8::kExternalFloat64Array, -500, 500);
14913 THREADED_TEST(Uint8ClampedArray) {
14914 TypedArrayTestHelper<uint8_t,
14915 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
14916 v8::kExternalUint8ClampedArray, 0, 0xFF);
14920 THREADED_TEST(DataView) {
14921 const int kSize = 50;
14923 i::ScopedVector<uint8_t> backing_store(kSize+2);
14926 v8::Isolate* isolate = env->GetIsolate();
14927 v8::HandleScope handle_scope(isolate);
14929 Local<v8::ArrayBuffer> ab =
14930 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
14931 Local<v8::DataView> dv =
14932 v8::DataView::New(ab, 2, kSize);
14933 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
14934 CHECK_EQ(2u, dv->ByteOffset());
14935 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
14936 CHECK(ab->Equals(dv->Buffer()));
14940 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
14941 THREADED_TEST(Is##View) { \
14942 LocalContext env; \
14943 v8::Isolate* isolate = env->GetIsolate(); \
14944 v8::HandleScope handle_scope(isolate); \
14946 Handle<Value> result = CompileRun( \
14947 "var ab = new ArrayBuffer(128);" \
14948 "new " #View "(ab)"); \
14949 CHECK(result->IsArrayBufferView()); \
14950 CHECK(result->Is##View()); \
14951 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
14954 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
14955 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
14956 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
14957 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
14958 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
14959 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
14960 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
14961 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
14962 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
14963 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
14965 #undef IS_ARRAY_BUFFER_VIEW_TEST
14969 THREADED_TEST(ScriptContextDependence) {
14971 v8::HandleScope scope(c1->GetIsolate());
14972 const char *source = "foo";
14973 v8::Handle<v8::Script> dep = v8_compile(source);
14974 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
14975 c1->GetIsolate(), source));
14976 v8::Handle<v8::UnboundScript> indep =
14977 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
14978 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
14979 v8::Integer::New(c1->GetIsolate(), 100));
14980 CHECK_EQ(dep->Run()->Int32Value(), 100);
14981 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
14983 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
14984 v8::Integer::New(c2->GetIsolate(), 101));
14985 CHECK_EQ(dep->Run()->Int32Value(), 100);
14986 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
14990 THREADED_TEST(StackTrace) {
14991 LocalContext context;
14992 v8::HandleScope scope(context->GetIsolate());
14993 v8::TryCatch try_catch;
14994 const char *source = "function foo() { FAIL.FAIL; }; foo();";
14995 v8::Handle<v8::String> src =
14996 v8::String::NewFromUtf8(context->GetIsolate(), source);
14997 v8::Handle<v8::String> origin =
14998 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
14999 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
15000 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
15001 ->BindToCurrentContext()
15003 CHECK(try_catch.HasCaught());
15004 v8::String::Utf8Value stack(try_catch.StackTrace());
15005 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
15009 // Checks that a StackFrame has certain expected values.
15010 void checkStackFrame(const char* expected_script_name,
15011 const char* expected_func_name, int expected_line_number,
15012 int expected_column, bool is_eval, bool is_constructor,
15013 v8::Handle<v8::StackFrame> frame) {
15014 v8::HandleScope scope(CcTest::isolate());
15015 v8::String::Utf8Value func_name(frame->GetFunctionName());
15016 v8::String::Utf8Value script_name(frame->GetScriptName());
15017 if (*script_name == NULL) {
15018 // The situation where there is no associated script, like for evals.
15019 CHECK(expected_script_name == NULL);
15021 CHECK(strstr(*script_name, expected_script_name) != NULL);
15023 CHECK(strstr(*func_name, expected_func_name) != NULL);
15024 CHECK_EQ(expected_line_number, frame->GetLineNumber());
15025 CHECK_EQ(expected_column, frame->GetColumn());
15026 CHECK_EQ(is_eval, frame->IsEval());
15027 CHECK_EQ(is_constructor, frame->IsConstructor());
15031 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
15032 v8::HandleScope scope(args.GetIsolate());
15033 const char* origin = "capture-stack-trace-test";
15034 const int kOverviewTest = 1;
15035 const int kDetailedTest = 2;
15037 DCHECK(args.Length() == 1);
15039 int testGroup = args[0]->Int32Value();
15040 if (testGroup == kOverviewTest) {
15041 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15042 args.GetIsolate(), 10, v8::StackTrace::kOverview);
15043 CHECK_EQ(4, stackTrace->GetFrameCount());
15044 checkStackFrame(origin, "bar", 2, 10, false, false,
15045 stackTrace->GetFrame(0));
15046 checkStackFrame(origin, "foo", 6, 3, false, false,
15047 stackTrace->GetFrame(1));
15048 // This is the source string inside the eval which has the call to foo.
15049 checkStackFrame(NULL, "", 1, 5, false, false,
15050 stackTrace->GetFrame(2));
15051 // The last frame is an anonymous function which has the initial eval call.
15052 checkStackFrame(origin, "", 8, 7, false, false,
15053 stackTrace->GetFrame(3));
15055 CHECK(stackTrace->AsArray()->IsArray());
15056 } else if (testGroup == kDetailedTest) {
15057 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15058 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15059 CHECK_EQ(4, stackTrace->GetFrameCount());
15060 checkStackFrame(origin, "bat", 4, 22, false, false,
15061 stackTrace->GetFrame(0));
15062 checkStackFrame(origin, "baz", 8, 3, false, true,
15063 stackTrace->GetFrame(1));
15064 bool is_eval = true;
15065 // This is the source string inside the eval which has the call to baz.
15066 checkStackFrame(NULL, "", 1, 5, is_eval, false,
15067 stackTrace->GetFrame(2));
15068 // The last frame is an anonymous function which has the initial eval call.
15069 checkStackFrame(origin, "", 10, 1, false, false,
15070 stackTrace->GetFrame(3));
15072 CHECK(stackTrace->AsArray()->IsArray());
15077 // Tests the C++ StackTrace API.
15078 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
15079 // THREADED_TEST(CaptureStackTrace) {
15080 TEST(CaptureStackTrace) {
15081 v8::Isolate* isolate = CcTest::isolate();
15082 v8::HandleScope scope(isolate);
15083 v8::Handle<v8::String> origin =
15084 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
15085 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15086 templ->Set(v8_str("AnalyzeStackInNativeCode"),
15087 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
15088 LocalContext context(0, templ);
15090 // Test getting OVERVIEW information. Should ignore information that is not
15091 // script name, function name, line number, and column offset.
15092 const char *overview_source =
15093 "function bar() {\n"
15094 " var y; AnalyzeStackInNativeCode(1);\n"
15096 "function foo() {\n"
15100 "var x;eval('new foo();');";
15101 v8::Handle<v8::String> overview_src =
15102 v8::String::NewFromUtf8(isolate, overview_source);
15103 v8::ScriptCompiler::Source script_source(overview_src,
15104 v8::ScriptOrigin(origin));
15105 v8::Handle<Value> overview_result(
15106 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
15107 ->BindToCurrentContext()
15109 CHECK(!overview_result.IsEmpty());
15110 CHECK(overview_result->IsObject());
15112 // Test getting DETAILED information.
15113 const char *detailed_source =
15114 "function bat() {AnalyzeStackInNativeCode(2);\n"
15117 "function baz() {\n"
15120 "eval('new baz();');";
15121 v8::Handle<v8::String> detailed_src =
15122 v8::String::NewFromUtf8(isolate, detailed_source);
15123 // Make the script using a non-zero line and column offset.
15124 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
15125 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
15126 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
15127 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
15128 v8::Handle<v8::UnboundScript> detailed_script(
15129 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
15130 v8::Handle<Value> detailed_result(
15131 detailed_script->BindToCurrentContext()->Run());
15132 CHECK(!detailed_result.IsEmpty());
15133 CHECK(detailed_result->IsObject());
15137 static void StackTraceForUncaughtExceptionListener(
15138 v8::Handle<v8::Message> message,
15139 v8::Handle<Value>) {
15141 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15142 CHECK_EQ(2, stack_trace->GetFrameCount());
15143 checkStackFrame("origin", "foo", 2, 3, false, false,
15144 stack_trace->GetFrame(0));
15145 checkStackFrame("origin", "bar", 5, 3, false, false,
15146 stack_trace->GetFrame(1));
15150 TEST(CaptureStackTraceForUncaughtException) {
15153 v8::HandleScope scope(env->GetIsolate());
15154 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
15155 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15157 CompileRunWithOrigin(
15158 "function foo() {\n"
15161 "function bar() {\n"
15165 v8::Local<v8::Object> global = env->Global();
15166 Local<Value> trouble = global->Get(v8_str("bar"));
15167 CHECK(trouble->IsFunction());
15168 Function::Cast(*trouble)->Call(global, 0, NULL);
15169 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15170 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
15171 CHECK_EQ(1, report_count);
15175 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
15178 v8::HandleScope scope(env->GetIsolate());
15180 // Create an Error object first.
15181 CompileRunWithOrigin(
15182 "function foo() {\n"
15183 "e=new Error('err');\n"
15185 "function bar() {\n"
15190 v8::Local<v8::Object> global = env->Global();
15191 Local<Value> trouble = global->Get(v8_str("bar"));
15192 CHECK(trouble->IsFunction());
15193 Function::Cast(*trouble)->Call(global, 0, NULL);
15195 // Enable capturing detailed stack trace late, and throw the exception.
15196 // The detailed stack trace should be extracted from the simple stack.
15197 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
15198 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15199 CompileRunWithOrigin("throw e", "origin");
15200 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15201 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
15202 CHECK_EQ(1, report_count);
15206 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
15208 v8::HandleScope scope(env->GetIsolate());
15209 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
15211 v8::StackTrace::kDetailed);
15214 "var setters = ['column', 'lineNumber', 'scriptName',\n"
15215 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
15216 " 'isConstructor'];\n"
15217 "for (var i = 0; i < setters.length; i++) {\n"
15218 " var prop = setters[i];\n"
15219 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
15221 CompileRun("throw 'exception';");
15222 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15226 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
15227 v8::Handle<v8::Value> data) {
15228 // Use the frame where JavaScript is called from.
15229 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15230 CHECK(!stack_trace.IsEmpty());
15231 int frame_count = stack_trace->GetFrameCount();
15232 CHECK_EQ(3, frame_count);
15233 int line_number[] = {1, 2, 5};
15234 for (int i = 0; i < frame_count; i++) {
15235 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
15240 // Test that we only return the stack trace at the site where the exception
15241 // is first thrown (not where it is rethrown).
15242 TEST(RethrowStackTrace) {
15244 v8::HandleScope scope(env->GetIsolate());
15245 // We make sure that
15246 // - the stack trace of the ReferenceError in g() is reported.
15247 // - the stack trace is not overwritten when e1 is rethrown by t().
15248 // - the stack trace of e2 does not overwrite that of e1.
15249 const char* source =
15250 "function g() { error; } \n"
15251 "function f() { g(); } \n"
15252 "function t(e) { throw e; } \n"
15255 "} catch (e1) { \n"
15258 " } catch (e2) { \n"
15262 v8::V8::AddMessageListener(RethrowStackTraceHandler);
15263 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15264 CompileRun(source);
15265 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15266 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
15270 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
15271 v8::Handle<v8::Value> data) {
15272 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15273 CHECK(!stack_trace.IsEmpty());
15274 int frame_count = stack_trace->GetFrameCount();
15275 CHECK_EQ(2, frame_count);
15276 int line_number[] = {3, 7};
15277 for (int i = 0; i < frame_count; i++) {
15278 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
15283 // Test that we do not recognize identity for primitive exceptions.
15284 TEST(RethrowPrimitiveStackTrace) {
15286 v8::HandleScope scope(env->GetIsolate());
15287 // We do not capture stack trace for non Error objects on creation time.
15288 // Instead, we capture the stack trace on last throw.
15289 const char* source =
15290 "function g() { throw 404; } \n"
15291 "function f() { g(); } \n"
15292 "function t(e) { throw e; } \n"
15295 "} catch (e1) { \n"
15298 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
15299 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15300 CompileRun(source);
15301 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15302 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
15306 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
15307 v8::Handle<v8::Value> data) {
15308 // Use the frame where JavaScript is called from.
15309 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15310 CHECK(!stack_trace.IsEmpty());
15311 CHECK_EQ(1, stack_trace->GetFrameCount());
15312 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
15316 // Test that the stack trace is captured when the error object is created and
15317 // not where it is thrown.
15318 TEST(RethrowExistingStackTrace) {
15320 v8::HandleScope scope(env->GetIsolate());
15321 const char* source =
15322 "var e = new Error(); \n"
15324 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
15325 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15326 CompileRun(source);
15327 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15328 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
15332 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
15333 v8::Handle<v8::Value> data) {
15334 // Use the frame where JavaScript is called from.
15335 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15336 CHECK(!stack_trace.IsEmpty());
15337 CHECK_EQ(1, stack_trace->GetFrameCount());
15338 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
15342 // Test that the stack trace is captured where the bogus Error object is thrown.
15343 TEST(RethrowBogusErrorStackTrace) {
15345 v8::HandleScope scope(env->GetIsolate());
15346 const char* source =
15347 "var e = {__proto__: new Error()} \n"
15349 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
15350 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
15351 CompileRun(source);
15352 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
15353 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
15357 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
15358 int promise_reject_counter = 0;
15359 int promise_revoke_counter = 0;
15360 int promise_reject_msg_line_number = -1;
15361 int promise_reject_msg_column_number = -1;
15362 int promise_reject_line_number = -1;
15363 int promise_reject_column_number = -1;
15364 int promise_reject_frame_count = -1;
15366 void PromiseRejectCallback(v8::PromiseRejectMessage reject_message) {
15367 if (reject_message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
15368 promise_reject_counter++;
15369 CcTest::global()->Set(v8_str("rejected"), reject_message.GetPromise());
15370 CcTest::global()->Set(v8_str("value"), reject_message.GetValue());
15371 v8::Handle<v8::Message> message =
15372 v8::Exception::CreateMessage(reject_message.GetValue());
15373 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
15375 promise_reject_msg_line_number = message->GetLineNumber();
15376 promise_reject_msg_column_number = message->GetStartColumn() + 1;
15378 if (!stack_trace.IsEmpty()) {
15379 promise_reject_frame_count = stack_trace->GetFrameCount();
15380 if (promise_reject_frame_count > 0) {
15381 CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
15382 promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
15383 promise_reject_column_number = stack_trace->GetFrame(0)->GetColumn();
15385 promise_reject_line_number = -1;
15386 promise_reject_column_number = -1;
15390 promise_revoke_counter++;
15391 CcTest::global()->Set(v8_str("revoked"), reject_message.GetPromise());
15392 CHECK(reject_message.GetValue().IsEmpty());
15397 v8::Handle<v8::Promise> GetPromise(const char* name) {
15398 return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
15402 v8::Handle<v8::Value> RejectValue() {
15403 return CcTest::global()->Get(v8_str("value"));
15407 void ResetPromiseStates() {
15408 promise_reject_counter = 0;
15409 promise_revoke_counter = 0;
15410 promise_reject_msg_line_number = -1;
15411 promise_reject_msg_column_number = -1;
15412 promise_reject_line_number = -1;
15413 promise_reject_column_number = -1;
15414 promise_reject_frame_count = -1;
15415 CcTest::global()->Set(v8_str("rejected"), v8_str(""));
15416 CcTest::global()->Set(v8_str("value"), v8_str(""));
15417 CcTest::global()->Set(v8_str("revoked"), v8_str(""));
15421 TEST(PromiseRejectCallback) {
15423 v8::Isolate* isolate = env->GetIsolate();
15424 v8::HandleScope scope(isolate);
15426 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
15428 ResetPromiseStates();
15430 // Create promise p0.
15433 "var p0 = new Promise( \n"
15434 " function(res, rej) { \n"
15435 " reject = rej; \n"
15438 CHECK(!GetPromise("p0")->HasHandler());
15439 CHECK_EQ(0, promise_reject_counter);
15440 CHECK_EQ(0, promise_revoke_counter);
15442 // Add resolve handler (and default reject handler) to p0.
15443 CompileRun("var p1 = p0.then(function(){});");
15444 CHECK(GetPromise("p0")->HasHandler());
15445 CHECK(!GetPromise("p1")->HasHandler());
15446 CHECK_EQ(0, promise_reject_counter);
15447 CHECK_EQ(0, promise_revoke_counter);
15450 CompileRun("reject('ppp');");
15451 CHECK(GetPromise("p0")->HasHandler());
15452 CHECK(!GetPromise("p1")->HasHandler());
15453 CHECK_EQ(1, promise_reject_counter);
15454 CHECK_EQ(0, promise_revoke_counter);
15455 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
15456 CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
15457 CHECK(RejectValue()->Equals(v8_str("ppp")));
15459 // Reject p0 again. Callback is not triggered again.
15460 CompileRun("reject();");
15461 CHECK(GetPromise("p0")->HasHandler());
15462 CHECK(!GetPromise("p1")->HasHandler());
15463 CHECK_EQ(1, promise_reject_counter);
15464 CHECK_EQ(0, promise_revoke_counter);
15466 // Add resolve handler to p1.
15467 CompileRun("var p2 = p1.then(function(){});");
15468 CHECK(GetPromise("p0")->HasHandler());
15469 CHECK(GetPromise("p1")->HasHandler());
15470 CHECK(!GetPromise("p2")->HasHandler());
15471 CHECK_EQ(2, promise_reject_counter);
15472 CHECK_EQ(1, promise_revoke_counter);
15473 CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
15474 CHECK(RejectValue()->Equals(v8_str("ppp")));
15475 CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
15477 ResetPromiseStates();
15479 // Create promise q0.
15481 "var q0 = new Promise( \n"
15482 " function(res, rej) { \n"
15483 " reject = rej; \n"
15486 CHECK(!GetPromise("q0")->HasHandler());
15487 CHECK_EQ(0, promise_reject_counter);
15488 CHECK_EQ(0, promise_revoke_counter);
15490 // Add reject handler to q0.
15491 CompileRun("var q1 = q0.catch(function() {});");
15492 CHECK(GetPromise("q0")->HasHandler());
15493 CHECK(!GetPromise("q1")->HasHandler());
15494 CHECK_EQ(0, promise_reject_counter);
15495 CHECK_EQ(0, promise_revoke_counter);
15498 CompileRun("reject('qq')");
15499 CHECK(GetPromise("q0")->HasHandler());
15500 CHECK(!GetPromise("q1")->HasHandler());
15501 CHECK_EQ(0, promise_reject_counter);
15502 CHECK_EQ(0, promise_revoke_counter);
15504 // Add a new reject handler, which rejects by returning Promise.reject().
15505 // The returned promise q_ triggers a reject callback at first, only to
15506 // revoke it when returning it causes q2 to be rejected.
15509 "var q2 = q0.catch( \n"
15511 " q_ = Promise.reject('qqq'); \n"
15515 CHECK(GetPromise("q0")->HasHandler());
15516 CHECK(!GetPromise("q1")->HasHandler());
15517 CHECK(!GetPromise("q2")->HasHandler());
15518 CHECK(GetPromise("q_")->HasHandler());
15519 CHECK_EQ(2, promise_reject_counter);
15520 CHECK_EQ(1, promise_revoke_counter);
15521 CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
15522 CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
15523 CHECK(RejectValue()->Equals(v8_str("qqq")));
15525 // Add a reject handler to the resolved q1, which rejects by throwing.
15527 "var q3 = q1.then( \n"
15529 " throw 'qqqq'; \n"
15532 CHECK(GetPromise("q0")->HasHandler());
15533 CHECK(GetPromise("q1")->HasHandler());
15534 CHECK(!GetPromise("q2")->HasHandler());
15535 CHECK(!GetPromise("q3")->HasHandler());
15536 CHECK_EQ(3, promise_reject_counter);
15537 CHECK_EQ(1, promise_revoke_counter);
15538 CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
15539 CHECK(RejectValue()->Equals(v8_str("qqqq")));
15541 ResetPromiseStates();
15543 // Create promise r0, which has three handlers, two of which handle rejects.
15545 "var r0 = new Promise( \n"
15546 " function(res, rej) { \n"
15547 " reject = rej; \n"
15550 "var r1 = r0.catch(function() {}); \n"
15551 "var r2 = r0.then(function() {}); \n"
15552 "var r3 = r0.then(function() {}, \n"
15553 " function() {}); \n");
15554 CHECK(GetPromise("r0")->HasHandler());
15555 CHECK(!GetPromise("r1")->HasHandler());
15556 CHECK(!GetPromise("r2")->HasHandler());
15557 CHECK(!GetPromise("r3")->HasHandler());
15558 CHECK_EQ(0, promise_reject_counter);
15559 CHECK_EQ(0, promise_revoke_counter);
15562 CompileRun("reject('rrr')");
15563 CHECK(GetPromise("r0")->HasHandler());
15564 CHECK(!GetPromise("r1")->HasHandler());
15565 CHECK(!GetPromise("r2")->HasHandler());
15566 CHECK(!GetPromise("r3")->HasHandler());
15567 CHECK_EQ(1, promise_reject_counter);
15568 CHECK_EQ(0, promise_revoke_counter);
15569 CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
15570 CHECK(RejectValue()->Equals(v8_str("rrr")));
15572 // Add reject handler to r2.
15573 CompileRun("var r4 = r2.catch(function() {});");
15574 CHECK(GetPromise("r0")->HasHandler());
15575 CHECK(!GetPromise("r1")->HasHandler());
15576 CHECK(GetPromise("r2")->HasHandler());
15577 CHECK(!GetPromise("r3")->HasHandler());
15578 CHECK(!GetPromise("r4")->HasHandler());
15579 CHECK_EQ(1, promise_reject_counter);
15580 CHECK_EQ(1, promise_revoke_counter);
15581 CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
15582 CHECK(RejectValue()->Equals(v8_str("rrr")));
15584 // Add reject handlers to r4.
15585 CompileRun("var r5 = r4.then(function() {}, function() {});");
15586 CHECK(GetPromise("r0")->HasHandler());
15587 CHECK(!GetPromise("r1")->HasHandler());
15588 CHECK(GetPromise("r2")->HasHandler());
15589 CHECK(!GetPromise("r3")->HasHandler());
15590 CHECK(GetPromise("r4")->HasHandler());
15591 CHECK(!GetPromise("r5")->HasHandler());
15592 CHECK_EQ(1, promise_reject_counter);
15593 CHECK_EQ(1, promise_revoke_counter);
15595 ResetPromiseStates();
15597 // Create promise s0, which has three handlers, none of which handle rejects.
15599 "var s0 = new Promise( \n"
15600 " function(res, rej) { \n"
15601 " reject = rej; \n"
15604 "var s1 = s0.then(function() {}); \n"
15605 "var s2 = s0.then(function() {}); \n"
15606 "var s3 = s0.then(function() {}); \n");
15607 CHECK(GetPromise("s0")->HasHandler());
15608 CHECK(!GetPromise("s1")->HasHandler());
15609 CHECK(!GetPromise("s2")->HasHandler());
15610 CHECK(!GetPromise("s3")->HasHandler());
15611 CHECK_EQ(0, promise_reject_counter);
15612 CHECK_EQ(0, promise_revoke_counter);
15615 CompileRun("reject('sss')");
15616 CHECK(GetPromise("s0")->HasHandler());
15617 CHECK(!GetPromise("s1")->HasHandler());
15618 CHECK(!GetPromise("s2")->HasHandler());
15619 CHECK(!GetPromise("s3")->HasHandler());
15620 CHECK_EQ(3, promise_reject_counter);
15621 CHECK_EQ(0, promise_revoke_counter);
15622 CHECK(RejectValue()->Equals(v8_str("sss")));
15624 // Test stack frames.
15625 V8::SetCaptureStackTraceForUncaughtExceptions(true);
15627 ResetPromiseStates();
15629 // Create promise t0, which is rejected in the constructor with an error.
15630 CompileRunWithOrigin(
15631 "var t0 = new Promise( \n"
15632 " function(res, rej) { \n"
15633 " reference_error; \n"
15637 CHECK(!GetPromise("t0")->HasHandler());
15638 CHECK_EQ(1, promise_reject_counter);
15639 CHECK_EQ(0, promise_revoke_counter);
15640 CHECK_EQ(2, promise_reject_frame_count);
15641 CHECK_EQ(3, promise_reject_line_number);
15642 CHECK_EQ(5, promise_reject_column_number);
15643 CHECK_EQ(3, promise_reject_msg_line_number);
15644 CHECK_EQ(5, promise_reject_msg_column_number);
15646 ResetPromiseStates();
15648 // Create promise u0 and chain u1 to it, which is rejected via throw.
15649 CompileRunWithOrigin(
15650 "var u0 = Promise.resolve(); \n"
15651 "var u1 = u0.then( \n"
15653 " (function() { \n"
15654 " throw new Error(); \n"
15659 CHECK(GetPromise("u0")->HasHandler());
15660 CHECK(!GetPromise("u1")->HasHandler());
15661 CHECK_EQ(1, promise_reject_counter);
15662 CHECK_EQ(0, promise_revoke_counter);
15663 CHECK_EQ(2, promise_reject_frame_count);
15664 CHECK_EQ(5, promise_reject_line_number);
15665 CHECK_EQ(23, promise_reject_column_number);
15666 CHECK_EQ(5, promise_reject_msg_line_number);
15667 CHECK_EQ(23, promise_reject_msg_column_number);
15669 // Throw in u3, which handles u1's rejection.
15670 CompileRunWithOrigin(
15671 "function f() { \n"
15672 " return (function() { \n"
15673 " return new Error(); \n"
15676 "var u2 = Promise.reject(f()); \n"
15677 "var u3 = u1.catch( \n"
15683 CHECK(GetPromise("u0")->HasHandler());
15684 CHECK(GetPromise("u1")->HasHandler());
15685 CHECK(GetPromise("u2")->HasHandler());
15686 CHECK(!GetPromise("u3")->HasHandler());
15687 CHECK_EQ(3, promise_reject_counter);
15688 CHECK_EQ(2, promise_revoke_counter);
15689 CHECK_EQ(3, promise_reject_frame_count);
15690 CHECK_EQ(3, promise_reject_line_number);
15691 CHECK_EQ(12, promise_reject_column_number);
15692 CHECK_EQ(3, promise_reject_msg_line_number);
15693 CHECK_EQ(12, promise_reject_msg_column_number);
15695 ResetPromiseStates();
15697 // Create promise rejected promise v0, which is incorrectly handled by v1
15698 // via chaining cycle.
15699 CompileRunWithOrigin(
15700 "var v0 = Promise.reject(); \n"
15701 "var v1 = v0.catch( \n"
15707 CHECK(GetPromise("v0")->HasHandler());
15708 CHECK(!GetPromise("v1")->HasHandler());
15709 CHECK_EQ(2, promise_reject_counter);
15710 CHECK_EQ(1, promise_revoke_counter);
15711 CHECK_EQ(0, promise_reject_frame_count);
15712 CHECK_EQ(-1, promise_reject_line_number);
15713 CHECK_EQ(-1, promise_reject_column_number);
15715 ResetPromiseStates();
15717 // Create promise t1, which rejects by throwing syntax error from eval.
15718 CompileRunWithOrigin(
15719 "var t1 = new Promise( \n"
15720 " function(res, rej) { \n"
15721 " var content = '\\n\\\n"
15723 " eval(content); \n"
15727 CHECK(!GetPromise("t1")->HasHandler());
15728 CHECK_EQ(1, promise_reject_counter);
15729 CHECK_EQ(0, promise_revoke_counter);
15730 CHECK_EQ(2, promise_reject_frame_count);
15731 CHECK_EQ(5, promise_reject_line_number);
15732 CHECK_EQ(10, promise_reject_column_number);
15733 CHECK_EQ(2, promise_reject_msg_line_number);
15734 CHECK_EQ(7, promise_reject_msg_column_number);
15738 void AnalyzeStackOfEvalWithSourceURL(
15739 const v8::FunctionCallbackInfo<v8::Value>& args) {
15740 v8::HandleScope scope(args.GetIsolate());
15741 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15742 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15743 CHECK_EQ(5, stackTrace->GetFrameCount());
15744 v8::Handle<v8::String> url = v8_str("eval_url");
15745 for (int i = 0; i < 3; i++) {
15746 v8::Handle<v8::String> name =
15747 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15748 CHECK(!name.IsEmpty());
15749 CHECK(url->Equals(name));
15754 TEST(SourceURLInStackTrace) {
15755 v8::Isolate* isolate = CcTest::isolate();
15756 v8::HandleScope scope(isolate);
15757 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15758 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
15759 v8::FunctionTemplate::New(isolate,
15760 AnalyzeStackOfEvalWithSourceURL));
15761 LocalContext context(0, templ);
15763 const char *source =
15764 "function outer() {\n"
15765 "function bar() {\n"
15766 " AnalyzeStackOfEvalWithSourceURL();\n"
15768 "function foo() {\n"
15774 "eval('(' + outer +')()%s');";
15776 i::ScopedVector<char> code(1024);
15777 i::SNPrintF(code, source, "//# sourceURL=eval_url");
15778 CHECK(CompileRun(code.start())->IsUndefined());
15779 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
15780 CHECK(CompileRun(code.start())->IsUndefined());
15784 static int scriptIdInStack[2];
15786 void AnalyzeScriptIdInStack(
15787 const v8::FunctionCallbackInfo<v8::Value>& args) {
15788 v8::HandleScope scope(args.GetIsolate());
15789 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15790 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
15791 CHECK_EQ(2, stackTrace->GetFrameCount());
15792 for (int i = 0; i < 2; i++) {
15793 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
15798 TEST(ScriptIdInStackTrace) {
15799 v8::Isolate* isolate = CcTest::isolate();
15800 v8::HandleScope scope(isolate);
15801 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15802 templ->Set(v8_str("AnalyzeScriptIdInStack"),
15803 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
15804 LocalContext context(0, templ);
15806 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
15808 "function foo() {\n"
15809 " AnalyzeScriptIdInStack();"
15812 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
15814 for (int i = 0; i < 2; i++) {
15815 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
15816 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
15821 void AnalyzeStackOfInlineScriptWithSourceURL(
15822 const v8::FunctionCallbackInfo<v8::Value>& args) {
15823 v8::HandleScope scope(args.GetIsolate());
15824 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15825 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15826 CHECK_EQ(4, stackTrace->GetFrameCount());
15827 v8::Handle<v8::String> url = v8_str("url");
15828 for (int i = 0; i < 3; i++) {
15829 v8::Handle<v8::String> name =
15830 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15831 CHECK(!name.IsEmpty());
15832 CHECK(url->Equals(name));
15837 TEST(InlineScriptWithSourceURLInStackTrace) {
15838 v8::Isolate* isolate = CcTest::isolate();
15839 v8::HandleScope scope(isolate);
15840 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15841 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
15842 v8::FunctionTemplate::New(
15843 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
15844 LocalContext context(0, templ);
15846 const char *source =
15847 "function outer() {\n"
15848 "function bar() {\n"
15849 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
15851 "function foo() {\n"
15859 i::ScopedVector<char> code(1024);
15860 i::SNPrintF(code, source, "//# sourceURL=source_url");
15861 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15862 i::SNPrintF(code, source, "//@ sourceURL=source_url");
15863 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
15867 void AnalyzeStackOfDynamicScriptWithSourceURL(
15868 const v8::FunctionCallbackInfo<v8::Value>& args) {
15869 v8::HandleScope scope(args.GetIsolate());
15870 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
15871 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
15872 CHECK_EQ(4, stackTrace->GetFrameCount());
15873 v8::Handle<v8::String> url = v8_str("source_url");
15874 for (int i = 0; i < 3; i++) {
15875 v8::Handle<v8::String> name =
15876 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
15877 CHECK(!name.IsEmpty());
15878 CHECK(url->Equals(name));
15883 TEST(DynamicWithSourceURLInStackTrace) {
15884 v8::Isolate* isolate = CcTest::isolate();
15885 v8::HandleScope scope(isolate);
15886 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15887 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
15888 v8::FunctionTemplate::New(
15889 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
15890 LocalContext context(0, templ);
15892 const char *source =
15893 "function outer() {\n"
15894 "function bar() {\n"
15895 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
15897 "function foo() {\n"
15905 i::ScopedVector<char> code(1024);
15906 i::SNPrintF(code, source, "//# sourceURL=source_url");
15907 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15908 i::SNPrintF(code, source, "//@ sourceURL=source_url");
15909 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
15913 TEST(DynamicWithSourceURLInStackTraceString) {
15914 LocalContext context;
15915 v8::HandleScope scope(context->GetIsolate());
15917 const char *source =
15918 "function outer() {\n"
15919 " function foo() {\n"
15926 i::ScopedVector<char> code(1024);
15927 i::SNPrintF(code, source, "//# sourceURL=source_url");
15928 v8::TryCatch try_catch;
15929 CompileRunWithOrigin(code.start(), "", 0, 0);
15930 CHECK(try_catch.HasCaught());
15931 v8::String::Utf8Value stack(try_catch.StackTrace());
15932 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
15936 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15937 LocalContext context;
15938 v8::HandleScope scope(context->GetIsolate());
15940 const char *source =
15941 "function outer() {\n"
15942 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
15943 " //# sourceURL=source_url\";\n"
15944 " eval(scriptContents);\n"
15947 "//# sourceURL=outer_url";
15949 v8::TryCatch try_catch;
15950 CompileRun(source);
15951 CHECK(try_catch.HasCaught());
15953 Local<v8::Message> message = try_catch.Message();
15954 Handle<Value> sourceURL =
15955 message->GetScriptOrigin().ResourceName();
15956 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15960 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
15961 LocalContext context;
15962 v8::HandleScope scope(context->GetIsolate());
15964 const char *source =
15965 "function outer() {\n"
15966 " var scriptContents = \"function boo(){ boo(); }\\\n"
15967 " //# sourceURL=source_url\";\n"
15968 " eval(scriptContents);\n"
15971 "//# sourceURL=outer_url";
15973 v8::TryCatch try_catch;
15974 CompileRun(source);
15975 CHECK(try_catch.HasCaught());
15977 Local<v8::Message> message = try_catch.Message();
15978 Handle<Value> sourceURL =
15979 message->GetScriptOrigin().ResourceName();
15980 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(sourceURL), "source_url"));
15984 static void CreateGarbageInOldSpace() {
15985 i::Factory* factory = CcTest::i_isolate()->factory();
15986 v8::HandleScope scope(CcTest::isolate());
15987 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
15988 for (int i = 0; i < 1000; i++) {
15989 factory->NewFixedArray(1000, i::TENURED);
15994 // Test that idle notification can be handled and eventually returns true.
15995 TEST(IdleNotification) {
15996 const intptr_t MB = 1024 * 1024;
15997 const int IdlePauseInMs = 1000;
15999 v8::HandleScope scope(env->GetIsolate());
16000 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
16001 CreateGarbageInOldSpace();
16002 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
16003 CHECK_GT(size_with_garbage, initial_size + MB);
16004 bool finished = false;
16005 for (int i = 0; i < 200 && !finished; i++) {
16006 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
16008 intptr_t final_size = CcTest::heap()->SizeOfObjects();
16010 CHECK_LT(final_size, initial_size + 1);
16014 // Test that idle notification can be handled and eventually collects garbage.
16015 TEST(IdleNotificationWithSmallHint) {
16016 const intptr_t MB = 1024 * 1024;
16017 const int IdlePauseInMs = 900;
16019 v8::HandleScope scope(env->GetIsolate());
16020 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
16021 CreateGarbageInOldSpace();
16022 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
16023 CHECK_GT(size_with_garbage, initial_size + MB);
16024 bool finished = false;
16025 for (int i = 0; i < 200 && !finished; i++) {
16026 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
16028 intptr_t final_size = CcTest::heap()->SizeOfObjects();
16030 CHECK_LT(final_size, initial_size + 1);
16034 // Test that idle notification can be handled and eventually collects garbage.
16035 TEST(IdleNotificationWithLargeHint) {
16036 const intptr_t MB = 1024 * 1024;
16037 const int IdlePauseInMs = 900;
16039 v8::HandleScope scope(env->GetIsolate());
16040 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
16041 CreateGarbageInOldSpace();
16042 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
16043 CHECK_GT(size_with_garbage, initial_size + MB);
16044 bool finished = false;
16045 for (int i = 0; i < 200 && !finished; i++) {
16046 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
16048 intptr_t final_size = CcTest::heap()->SizeOfObjects();
16050 CHECK_LT(final_size, initial_size + 1);
16054 TEST(Regress2333) {
16056 for (int i = 0; i < 3; i++) {
16057 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
16061 static uint32_t* stack_limit;
16063 static void GetStackLimitCallback(
16064 const v8::FunctionCallbackInfo<v8::Value>& args) {
16065 stack_limit = reinterpret_cast<uint32_t*>(
16066 CcTest::i_isolate()->stack_guard()->real_climit());
16070 // Uses the address of a local variable to determine the stack top now.
16071 // Given a size, returns an address that is that far from the current
16073 static uint32_t* ComputeStackLimit(uint32_t size) {
16074 uint32_t* answer = &size - (size / sizeof(size));
16075 // If the size is very large and the stack is very near the bottom of
16076 // memory then the calculation above may wrap around and give an address
16077 // that is above the (downwards-growing) stack. In that case we return
16078 // a very low address.
16079 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
16084 // We need at least 165kB for an x64 debug build with clang and ASAN.
16085 static const int stack_breathing_room = 256 * i::KB;
16088 TEST(SetStackLimit) {
16089 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
16091 // Set stack limit.
16092 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
16094 // Execute a script.
16096 v8::HandleScope scope(env->GetIsolate());
16097 Local<v8::FunctionTemplate> fun_templ =
16098 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
16099 Local<Function> fun = fun_templ->GetFunction();
16100 env->Global()->Set(v8_str("get_stack_limit"), fun);
16101 CompileRun("get_stack_limit();");
16103 CHECK(stack_limit == set_limit);
16107 TEST(SetStackLimitInThread) {
16108 uint32_t* set_limit;
16110 v8::Locker locker(CcTest::isolate());
16111 set_limit = ComputeStackLimit(stack_breathing_room);
16113 // Set stack limit.
16114 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
16116 // Execute a script.
16117 v8::HandleScope scope(CcTest::isolate());
16119 Local<v8::FunctionTemplate> fun_templ =
16120 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
16121 Local<Function> fun = fun_templ->GetFunction();
16122 env->Global()->Set(v8_str("get_stack_limit"), fun);
16123 CompileRun("get_stack_limit();");
16125 CHECK(stack_limit == set_limit);
16128 v8::Locker locker(CcTest::isolate());
16129 CHECK(stack_limit == set_limit);
16134 THREADED_TEST(GetHeapStatistics) {
16136 v8::HandleScope scope(c1->GetIsolate());
16137 v8::HeapStatistics heap_statistics;
16138 CHECK_EQ(0u, heap_statistics.total_heap_size());
16139 CHECK_EQ(0u, heap_statistics.used_heap_size());
16140 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
16141 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
16142 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
16146 class VisitorImpl : public v8::ExternalResourceVisitor {
16148 explicit VisitorImpl(TestResource** resource) {
16149 for (int i = 0; i < 4; i++) {
16150 resource_[i] = resource[i];
16151 found_resource_[i] = false;
16154 virtual ~VisitorImpl() {}
16155 virtual void VisitExternalString(v8::Handle<v8::String> string) {
16156 if (!string->IsExternal()) {
16157 CHECK(string->IsExternalOneByte());
16160 v8::String::ExternalStringResource* resource =
16161 string->GetExternalStringResource();
16163 for (int i = 0; i < 4; i++) {
16164 if (resource_[i] == resource) {
16165 CHECK(!found_resource_[i]);
16166 found_resource_[i] = true;
16170 void CheckVisitedResources() {
16171 for (int i = 0; i < 4; i++) {
16172 CHECK(found_resource_[i]);
16177 v8::String::ExternalStringResource* resource_[4];
16178 bool found_resource_[4];
16182 TEST(ExternalizeOldSpaceTwoByteCons) {
16183 v8::Isolate* isolate = CcTest::isolate();
16185 v8::HandleScope scope(isolate);
16186 v8::Local<v8::String> cons =
16187 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
16188 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
16189 CcTest::heap()->CollectAllAvailableGarbage();
16190 CHECK(CcTest::heap()->old_pointer_space()->Contains(
16191 *v8::Utils::OpenHandle(*cons)));
16193 TestResource* resource = new TestResource(
16194 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
16195 cons->MakeExternal(resource);
16197 CHECK(cons->IsExternal());
16198 CHECK_EQ(resource, cons->GetExternalStringResource());
16199 String::Encoding encoding;
16200 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
16201 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
16205 TEST(ExternalizeOldSpaceOneByteCons) {
16206 v8::Isolate* isolate = CcTest::isolate();
16208 v8::HandleScope scope(isolate);
16209 v8::Local<v8::String> cons =
16210 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
16211 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
16212 CcTest::heap()->CollectAllAvailableGarbage();
16213 CHECK(CcTest::heap()->old_pointer_space()->Contains(
16214 *v8::Utils::OpenHandle(*cons)));
16216 TestOneByteResource* resource =
16217 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
16218 cons->MakeExternal(resource);
16220 CHECK(cons->IsExternalOneByte());
16221 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
16222 String::Encoding encoding;
16223 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
16224 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
16228 TEST(VisitExternalStrings) {
16229 v8::Isolate* isolate = CcTest::isolate();
16231 v8::HandleScope scope(isolate);
16232 const char* string = "Some string";
16233 uint16_t* two_byte_string = AsciiToTwoByteString(string);
16234 TestResource* resource[4];
16235 resource[0] = new TestResource(two_byte_string);
16236 v8::Local<v8::String> string0 =
16237 v8::String::NewExternal(env->GetIsolate(), resource[0]);
16238 resource[1] = new TestResource(two_byte_string, NULL, false);
16239 v8::Local<v8::String> string1 =
16240 v8::String::NewExternal(env->GetIsolate(), resource[1]);
16242 // Externalized symbol.
16243 resource[2] = new TestResource(two_byte_string, NULL, false);
16244 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
16245 env->GetIsolate(), string, v8::String::kInternalizedString);
16246 CHECK(string2->MakeExternal(resource[2]));
16248 // Symbolized External.
16249 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
16250 v8::Local<v8::String> string3 =
16251 v8::String::NewExternal(env->GetIsolate(), resource[3]);
16252 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
16253 // Turn into a symbol.
16254 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
16255 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
16256 string3_i).is_null());
16257 CHECK(string3_i->IsInternalizedString());
16259 // We need to add usages for string* to avoid warnings in GCC 4.7
16260 CHECK(string0->IsExternal());
16261 CHECK(string1->IsExternal());
16262 CHECK(string2->IsExternal());
16263 CHECK(string3->IsExternal());
16265 VisitorImpl visitor(resource);
16266 v8::V8::VisitExternalResources(&visitor);
16267 visitor.CheckVisitedResources();
16271 TEST(ExternalStringCollectedAtTearDown) {
16273 v8::Isolate* isolate = v8::Isolate::New();
16274 { v8::Isolate::Scope isolate_scope(isolate);
16275 v8::HandleScope handle_scope(isolate);
16276 const char* s = "One string to test them all, one string to find them.";
16277 TestOneByteResource* inscription =
16278 new TestOneByteResource(i::StrDup(s), &destroyed);
16279 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
16280 // Ring is still alive. Orcs are roaming freely across our lands.
16281 CHECK_EQ(0, destroyed);
16285 isolate->Dispose();
16286 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
16287 CHECK_EQ(1, destroyed);
16291 TEST(ExternalInternalizedStringCollectedAtTearDown) {
16293 v8::Isolate* isolate = v8::Isolate::New();
16294 { v8::Isolate::Scope isolate_scope(isolate);
16295 LocalContext env(isolate);
16296 v8::HandleScope handle_scope(isolate);
16297 CompileRun("var ring = 'One string to test them all';");
16298 const char* s = "One string to test them all";
16299 TestOneByteResource* inscription =
16300 new TestOneByteResource(i::StrDup(s), &destroyed);
16301 v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
16302 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
16303 ring->MakeExternal(inscription);
16304 // Ring is still alive. Orcs are roaming freely across our lands.
16305 CHECK_EQ(0, destroyed);
16309 isolate->Dispose();
16310 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
16311 CHECK_EQ(1, destroyed);
16315 TEST(ExternalInternalizedStringCollectedAtGC) {
16316 // TODO(mvstanton): vector ics need weak support.
16317 if (i::FLAG_vector_ics) return;
16320 { LocalContext env;
16321 v8::HandleScope handle_scope(env->GetIsolate());
16322 CompileRun("var ring = 'One string to test them all';");
16323 const char* s = "One string to test them all";
16324 TestOneByteResource* inscription =
16325 new TestOneByteResource(i::StrDup(s), &destroyed);
16326 v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
16327 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
16328 ring->MakeExternal(inscription);
16329 // Ring is still alive. Orcs are roaming freely across our lands.
16330 CHECK_EQ(0, destroyed);
16334 // Garbage collector deals swift blows to evil.
16335 CcTest::i_isolate()->compilation_cache()->Clear();
16336 CcTest::heap()->CollectAllAvailableGarbage();
16338 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
16339 CHECK_EQ(1, destroyed);
16343 static double DoubleFromBits(uint64_t value) {
16345 i::MemCopy(&target, &value, sizeof(target));
16350 static uint64_t DoubleToBits(double value) {
16352 i::MemCopy(&target, &value, sizeof(target));
16357 static double DoubleToDateTime(double input) {
16358 double date_limit = 864e13;
16359 if (std::isnan(input) || input < -date_limit || input > date_limit) {
16360 return std::numeric_limits<double>::quiet_NaN();
16362 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
16366 // We don't have a consistent way to write 64-bit constants syntactically, so we
16367 // split them into two 32-bit constants and combine them programmatically.
16368 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
16369 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
16373 THREADED_TEST(QuietSignalingNaNs) {
16374 LocalContext context;
16375 v8::Isolate* isolate = context->GetIsolate();
16376 v8::HandleScope scope(isolate);
16377 v8::TryCatch try_catch;
16379 // Special double values.
16380 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
16381 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
16382 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
16383 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
16384 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
16385 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
16386 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
16388 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
16389 // on either side of the epoch.
16390 double date_limit = 864e13;
16392 double test_values[] = {
16414 int num_test_values = 20;
16416 for (int i = 0; i < num_test_values; i++) {
16417 double test_value = test_values[i];
16419 // Check that Number::New preserves non-NaNs and quiets SNaNs.
16420 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
16421 double stored_number = number->NumberValue();
16422 if (!std::isnan(test_value)) {
16423 CHECK_EQ(test_value, stored_number);
16425 uint64_t stored_bits = DoubleToBits(stored_number);
16426 // Check if quiet nan (bits 51..62 all set).
16427 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
16428 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
16429 // Most significant fraction bit for quiet nan is set to 0
16430 // on MIPS architecture. Allowed by IEEE-754.
16431 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
16433 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
16437 // Check that Date::New preserves non-NaNs in the date range and
16439 v8::Handle<v8::Value> date =
16440 v8::Date::New(isolate, test_value);
16441 double expected_stored_date = DoubleToDateTime(test_value);
16442 double stored_date = date->NumberValue();
16443 if (!std::isnan(expected_stored_date)) {
16444 CHECK_EQ(expected_stored_date, stored_date);
16446 uint64_t stored_bits = DoubleToBits(stored_date);
16447 // Check if quiet nan (bits 51..62 all set).
16448 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
16449 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
16450 // Most significant fraction bit for quiet nan is set to 0
16451 // on MIPS architecture. Allowed by IEEE-754.
16452 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
16454 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
16461 static void SpaghettiIncident(
16462 const v8::FunctionCallbackInfo<v8::Value>& args) {
16463 v8::HandleScope scope(args.GetIsolate());
16465 v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
16467 if (tc.HasCaught())
16472 // Test that an exception can be propagated down through a spaghetti
16473 // stack using ReThrow.
16474 THREADED_TEST(SpaghettiStackReThrow) {
16475 v8::Isolate* isolate = CcTest::isolate();
16476 v8::HandleScope scope(isolate);
16477 LocalContext context;
16478 context->Global()->Set(
16479 v8::String::NewFromUtf8(isolate, "s"),
16480 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
16481 v8::TryCatch try_catch;
16485 " toString: function () {"
16495 CHECK(try_catch.HasCaught());
16496 v8::String::Utf8Value value(try_catch.Exception());
16497 CHECK_EQ(0, strcmp(*value, "Hey!"));
16502 v8::V8::Initialize();
16503 v8::Isolate* isolate = CcTest::isolate();
16504 v8::HandleScope scope(isolate);
16505 v8::Local<Context> other_context;
16508 // Create a context used to keep the code from aging in the compilation
16510 other_context = Context::New(isolate);
16512 // Context-dependent context data creates reference from the compilation
16513 // cache to the global object.
16514 const char* source_simple = "1";
16516 v8::HandleScope scope(isolate);
16517 v8::Local<Context> context = Context::New(isolate);
16520 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
16521 context->SetEmbedderData(0, obj);
16522 CompileRun(source_simple);
16525 isolate->ContextDisposedNotification();
16526 for (gc_count = 1; gc_count < 10; gc_count++) {
16527 other_context->Enter();
16528 CompileRun(source_simple);
16529 other_context->Exit();
16530 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16531 if (GetGlobalObjectsCount() == 1) break;
16533 CHECK_GE(2, gc_count);
16534 CHECK_EQ(1, GetGlobalObjectsCount());
16536 // Eval in a function creates reference from the compilation cache to the
16538 const char* source_eval = "function f(){eval('1')}; f()";
16540 v8::HandleScope scope(isolate);
16541 v8::Local<Context> context = Context::New(isolate);
16544 CompileRun(source_eval);
16547 isolate->ContextDisposedNotification();
16548 for (gc_count = 1; gc_count < 10; gc_count++) {
16549 other_context->Enter();
16550 CompileRun(source_eval);
16551 other_context->Exit();
16552 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16553 if (GetGlobalObjectsCount() == 1) break;
16555 CHECK_GE(2, gc_count);
16556 CHECK_EQ(1, GetGlobalObjectsCount());
16558 // Looking up the line number for an exception creates reference from the
16559 // compilation cache to the global object.
16560 const char* source_exception = "function f(){throw 1;} f()";
16562 v8::HandleScope scope(isolate);
16563 v8::Local<Context> context = Context::New(isolate);
16566 v8::TryCatch try_catch;
16567 CompileRun(source_exception);
16568 CHECK(try_catch.HasCaught());
16569 v8::Handle<v8::Message> message = try_catch.Message();
16570 CHECK(!message.IsEmpty());
16571 CHECK_EQ(1, message->GetLineNumber());
16574 isolate->ContextDisposedNotification();
16575 for (gc_count = 1; gc_count < 10; gc_count++) {
16576 other_context->Enter();
16577 CompileRun(source_exception);
16578 other_context->Exit();
16579 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16580 if (GetGlobalObjectsCount() == 1) break;
16582 CHECK_GE(2, gc_count);
16583 CHECK_EQ(1, GetGlobalObjectsCount());
16585 isolate->ContextDisposedNotification();
16589 THREADED_TEST(ScriptOrigin) {
16591 v8::HandleScope scope(env->GetIsolate());
16592 v8::ScriptOrigin origin = v8::ScriptOrigin(
16593 v8::String::NewFromUtf8(env->GetIsolate(), "test"),
16594 v8::Integer::New(env->GetIsolate(), 1),
16595 v8::Integer::New(env->GetIsolate(), 1), v8::True(env->GetIsolate()),
16596 v8::Handle<v8::Integer>(), v8::True(env->GetIsolate()));
16597 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16598 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
16599 v8::Script::Compile(script, &origin)->Run();
16600 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16601 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16602 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16603 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16605 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
16606 CHECK_EQ(0, strcmp("test",
16607 *v8::String::Utf8Value(script_origin_f.ResourceName())));
16608 CHECK_EQ(1, script_origin_f.ResourceLineOffset()->Int32Value());
16609 CHECK(script_origin_f.ResourceIsSharedCrossOrigin()->Value());
16610 CHECK(script_origin_f.ResourceIsEmbedderDebugScript()->Value());
16612 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
16613 CHECK_EQ(0, strcmp("test",
16614 *v8::String::Utf8Value(script_origin_g.ResourceName())));
16615 CHECK_EQ(1, script_origin_g.ResourceLineOffset()->Int32Value());
16616 CHECK(script_origin_g.ResourceIsSharedCrossOrigin()->Value());
16617 CHECK(script_origin_g.ResourceIsEmbedderDebugScript()->Value());
16621 THREADED_TEST(FunctionGetInferredName) {
16623 v8::HandleScope scope(env->GetIsolate());
16624 v8::ScriptOrigin origin =
16625 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16626 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16628 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
16629 v8::Script::Compile(script, &origin)->Run();
16630 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16631 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16633 strcmp("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())));
16637 THREADED_TEST(FunctionGetDisplayName) {
16639 v8::HandleScope scope(env->GetIsolate());
16640 const char* code = "var error = false;"
16641 "function a() { this.x = 1; };"
16642 "a.displayName = 'display_a';"
16643 "var b = (function() {"
16644 " var f = function() { this.x = 2; };"
16645 " f.displayName = 'display_b';"
16648 "var c = function() {};"
16649 "c.__defineGetter__('displayName', function() {"
16651 " throw new Error();"
16654 "d.__defineGetter__('displayName', function() {"
16656 " return 'wrong_display_name';"
16659 "e.displayName = 'wrong_display_name';"
16660 "e.__defineSetter__('displayName', function() {"
16662 " throw new Error();"
16665 "f.displayName = { 'foo': 6, toString: function() {"
16667 " return 'wrong_display_name';"
16669 "var g = function() {"
16670 " arguments.callee.displayName = 'set_in_runtime';"
16673 v8::ScriptOrigin origin =
16674 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16675 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
16677 v8::Local<v8::Value> error =
16678 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
16679 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
16680 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
16681 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
16682 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
16683 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
16684 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
16685 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
16686 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
16687 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
16688 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
16689 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16690 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16691 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16692 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16693 CHECK_EQ(false, error->BooleanValue());
16694 CHECK_EQ(0, strcmp("display_a", *v8::String::Utf8Value(a->GetDisplayName())));
16695 CHECK_EQ(0, strcmp("display_b", *v8::String::Utf8Value(b->GetDisplayName())));
16696 CHECK(c->GetDisplayName()->IsUndefined());
16697 CHECK(d->GetDisplayName()->IsUndefined());
16698 CHECK(e->GetDisplayName()->IsUndefined());
16699 CHECK(f->GetDisplayName()->IsUndefined());
16701 0, strcmp("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName())));
16705 THREADED_TEST(ScriptLineNumber) {
16707 v8::HandleScope scope(env->GetIsolate());
16708 v8::ScriptOrigin origin =
16709 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
16710 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16711 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
16712 v8::Script::Compile(script, &origin)->Run();
16713 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16714 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16715 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16716 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16717 CHECK_EQ(0, f->GetScriptLineNumber());
16718 CHECK_EQ(2, g->GetScriptLineNumber());
16722 THREADED_TEST(ScriptColumnNumber) {
16724 v8::Isolate* isolate = env->GetIsolate();
16725 v8::HandleScope scope(isolate);
16726 v8::ScriptOrigin origin =
16727 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16728 v8::Integer::New(isolate, 3),
16729 v8::Integer::New(isolate, 2));
16730 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16731 isolate, "function foo() {}\n\n function bar() {}");
16732 v8::Script::Compile(script, &origin)->Run();
16733 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16734 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16735 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16736 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16737 CHECK_EQ(14, foo->GetScriptColumnNumber());
16738 CHECK_EQ(17, bar->GetScriptColumnNumber());
16742 THREADED_TEST(FunctionIsBuiltin) {
16744 v8::Isolate* isolate = env->GetIsolate();
16745 v8::HandleScope scope(isolate);
16746 v8::Local<v8::Function> f;
16747 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
16748 CHECK(f->IsBuiltin());
16749 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
16750 CHECK(f->IsBuiltin());
16751 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
16752 CHECK(f->IsBuiltin());
16753 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
16754 CHECK(f->IsBuiltin());
16755 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
16756 CHECK(!f->IsBuiltin());
16760 THREADED_TEST(FunctionGetScriptId) {
16762 v8::Isolate* isolate = env->GetIsolate();
16763 v8::HandleScope scope(isolate);
16764 v8::ScriptOrigin origin =
16765 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
16766 v8::Integer::New(isolate, 3),
16767 v8::Integer::New(isolate, 2));
16768 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
16769 isolate, "function foo() {}\n\n function bar() {}");
16770 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
16772 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
16773 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
16774 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
16775 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
16776 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
16777 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
16781 THREADED_TEST(FunctionGetBoundFunction) {
16783 v8::HandleScope scope(env->GetIsolate());
16784 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
16785 env->GetIsolate(), "test"));
16786 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
16788 "var a = new Object();\n"
16790 "function f () { return this.x };\n"
16791 "var g = f.bind(a);\n"
16793 v8::Script::Compile(script, &origin)->Run();
16794 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
16795 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
16796 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
16797 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
16798 CHECK(g->GetBoundFunction()->IsFunction());
16799 Local<v8::Function> original_function = Local<v8::Function>::Cast(
16800 g->GetBoundFunction());
16801 CHECK(f->GetName()->Equals(original_function->GetName()));
16802 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
16803 CHECK_EQ(f->GetScriptColumnNumber(),
16804 original_function->GetScriptColumnNumber());
16808 static void GetterWhichReturns42(
16809 Local<String> name,
16810 const v8::PropertyCallbackInfo<v8::Value>& info) {
16811 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16812 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16813 info.GetReturnValue().Set(v8_num(42));
16817 static void SetterWhichSetsYOnThisTo23(
16818 Local<String> name,
16819 Local<Value> value,
16820 const v8::PropertyCallbackInfo<void>& info) {
16821 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16822 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16823 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16827 void FooGetInterceptor(Local<Name> name,
16828 const v8::PropertyCallbackInfo<v8::Value>& info) {
16829 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16830 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16831 if (!name->Equals(v8_str("foo"))) return;
16832 info.GetReturnValue().Set(v8_num(42));
16836 void FooSetInterceptor(Local<Name> name, Local<Value> value,
16837 const v8::PropertyCallbackInfo<v8::Value>& info) {
16838 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
16839 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
16840 if (!name->Equals(v8_str("foo"))) return;
16841 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16842 info.GetReturnValue().Set(v8_num(23));
16846 TEST(SetterOnConstructorPrototype) {
16847 v8::Isolate* isolate = CcTest::isolate();
16848 v8::HandleScope scope(isolate);
16849 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16850 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16851 SetterWhichSetsYOnThisTo23);
16852 LocalContext context;
16853 context->Global()->Set(v8_str("P"), templ->NewInstance());
16854 CompileRun("function C1() {"
16857 "C1.prototype = P;"
16861 "C2.prototype = { };"
16862 "C2.prototype.__proto__ = P;");
16864 v8::Local<v8::Script> script;
16865 script = v8_compile("new C1();");
16866 for (int i = 0; i < 10; i++) {
16867 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16868 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16869 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16872 script = v8_compile("new C2();");
16873 for (int i = 0; i < 10; i++) {
16874 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16875 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
16876 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
16881 static void NamedPropertyGetterWhichReturns42(
16882 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
16883 info.GetReturnValue().Set(v8_num(42));
16887 static void NamedPropertySetterWhichSetsYOnThisTo23(
16888 Local<Name> name, Local<Value> value,
16889 const v8::PropertyCallbackInfo<v8::Value>& info) {
16890 if (name->Equals(v8_str("x"))) {
16891 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
16896 THREADED_TEST(InterceptorOnConstructorPrototype) {
16897 v8::Isolate* isolate = CcTest::isolate();
16898 v8::HandleScope scope(isolate);
16899 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16900 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
16901 NamedPropertyGetterWhichReturns42,
16902 NamedPropertySetterWhichSetsYOnThisTo23));
16903 LocalContext context;
16904 context->Global()->Set(v8_str("P"), templ->NewInstance());
16905 CompileRun("function C1() {"
16908 "C1.prototype = P;"
16912 "C2.prototype = { };"
16913 "C2.prototype.__proto__ = P;");
16915 v8::Local<v8::Script> script;
16916 script = v8_compile("new C1();");
16917 for (int i = 0; i < 10; i++) {
16918 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16919 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16920 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16923 script = v8_compile("new C2();");
16924 for (int i = 0; i < 10; i++) {
16925 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
16926 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
16927 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
16933 const char* source = "function C1() {"
16936 "C1.prototype = P;";
16938 LocalContext context;
16939 v8::Isolate* isolate = context->GetIsolate();
16940 v8::HandleScope scope(isolate);
16941 v8::Local<v8::Script> script;
16943 // Use a simple object as prototype.
16944 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
16945 prototype->Set(v8_str("y"), v8_num(42));
16946 context->Global()->Set(v8_str("P"), prototype);
16948 // This compile will add the code to the compilation cache.
16949 CompileRun(source);
16951 script = v8_compile("new C1();");
16952 // Allow enough iterations for the inobject slack tracking logic
16953 // to finalize instance size and install the fast construct stub.
16954 for (int i = 0; i < 256; i++) {
16955 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16956 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
16957 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
16960 // Use an API object with accessors as prototype.
16961 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
16962 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
16963 SetterWhichSetsYOnThisTo23);
16964 context->Global()->Set(v8_str("P"), templ->NewInstance());
16966 // This compile will get the code from the compilation cache.
16967 CompileRun(source);
16969 script = v8_compile("new C1();");
16970 for (int i = 0; i < 10; i++) {
16971 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
16972 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
16973 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
16977 v8::Isolate* gc_callbacks_isolate = NULL;
16978 int prologue_call_count = 0;
16979 int epilogue_call_count = 0;
16980 int prologue_call_count_second = 0;
16981 int epilogue_call_count_second = 0;
16982 int prologue_call_count_alloc = 0;
16983 int epilogue_call_count_alloc = 0;
16985 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
16986 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16987 ++prologue_call_count;
16991 void PrologueCallback(v8::Isolate* isolate,
16993 v8::GCCallbackFlags flags) {
16994 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
16995 CHECK_EQ(gc_callbacks_isolate, isolate);
16996 ++prologue_call_count;
17000 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
17001 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17002 ++epilogue_call_count;
17006 void EpilogueCallback(v8::Isolate* isolate,
17008 v8::GCCallbackFlags flags) {
17009 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17010 CHECK_EQ(gc_callbacks_isolate, isolate);
17011 ++epilogue_call_count;
17015 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
17016 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17017 ++prologue_call_count_second;
17021 void PrologueCallbackSecond(v8::Isolate* isolate,
17023 v8::GCCallbackFlags flags) {
17024 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17025 CHECK_EQ(gc_callbacks_isolate, isolate);
17026 ++prologue_call_count_second;
17030 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
17031 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17032 ++epilogue_call_count_second;
17036 void EpilogueCallbackSecond(v8::Isolate* isolate,
17038 v8::GCCallbackFlags flags) {
17039 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17040 CHECK_EQ(gc_callbacks_isolate, isolate);
17041 ++epilogue_call_count_second;
17045 void PrologueCallbackAlloc(v8::Isolate* isolate,
17047 v8::GCCallbackFlags flags) {
17048 v8::HandleScope scope(isolate);
17050 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17051 CHECK_EQ(gc_callbacks_isolate, isolate);
17052 ++prologue_call_count_alloc;
17054 // Simulate full heap to see if we will reenter this callback
17055 SimulateFullSpace(CcTest::heap()->new_space());
17057 Local<Object> obj = Object::New(isolate);
17058 CHECK(!obj.IsEmpty());
17060 CcTest::heap()->CollectAllGarbage(
17061 i::Heap::kAbortIncrementalMarkingMask);
17065 void EpilogueCallbackAlloc(v8::Isolate* isolate,
17067 v8::GCCallbackFlags flags) {
17068 v8::HandleScope scope(isolate);
17070 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
17071 CHECK_EQ(gc_callbacks_isolate, isolate);
17072 ++epilogue_call_count_alloc;
17074 // Simulate full heap to see if we will reenter this callback
17075 SimulateFullSpace(CcTest::heap()->new_space());
17077 Local<Object> obj = Object::New(isolate);
17078 CHECK(!obj.IsEmpty());
17080 CcTest::heap()->CollectAllGarbage(
17081 i::Heap::kAbortIncrementalMarkingMask);
17085 TEST(GCCallbacksOld) {
17086 LocalContext context;
17088 v8::V8::AddGCPrologueCallback(PrologueCallback);
17089 v8::V8::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 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
17096 v8::V8::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 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
17103 v8::V8::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 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
17110 v8::V8::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);
17119 TEST(GCCallbacks) {
17120 LocalContext context;
17121 v8::Isolate* isolate = context->GetIsolate();
17122 gc_callbacks_isolate = isolate;
17123 isolate->AddGCPrologueCallback(PrologueCallback);
17124 isolate->AddGCEpilogueCallback(EpilogueCallback);
17125 CHECK_EQ(0, prologue_call_count);
17126 CHECK_EQ(0, epilogue_call_count);
17127 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17128 CHECK_EQ(1, prologue_call_count);
17129 CHECK_EQ(1, epilogue_call_count);
17130 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
17131 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
17132 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17133 CHECK_EQ(2, prologue_call_count);
17134 CHECK_EQ(2, epilogue_call_count);
17135 CHECK_EQ(1, prologue_call_count_second);
17136 CHECK_EQ(1, epilogue_call_count_second);
17137 isolate->RemoveGCPrologueCallback(PrologueCallback);
17138 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
17139 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17140 CHECK_EQ(2, prologue_call_count);
17141 CHECK_EQ(2, epilogue_call_count);
17142 CHECK_EQ(2, prologue_call_count_second);
17143 CHECK_EQ(2, epilogue_call_count_second);
17144 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
17145 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
17146 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17147 CHECK_EQ(2, prologue_call_count);
17148 CHECK_EQ(2, epilogue_call_count);
17149 CHECK_EQ(2, prologue_call_count_second);
17150 CHECK_EQ(2, epilogue_call_count_second);
17152 CHECK_EQ(0, prologue_call_count_alloc);
17153 CHECK_EQ(0, epilogue_call_count_alloc);
17154 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
17155 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
17156 CcTest::heap()->CollectAllGarbage(
17157 i::Heap::kAbortIncrementalMarkingMask);
17158 CHECK_EQ(1, prologue_call_count_alloc);
17159 CHECK_EQ(1, epilogue_call_count_alloc);
17160 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
17161 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
17165 THREADED_TEST(AddToJSFunctionResultCache) {
17166 i::FLAG_stress_compaction = false;
17167 i::FLAG_allow_natives_syntax = true;
17168 v8::HandleScope scope(CcTest::isolate());
17170 LocalContext context;
17176 " var r0 = %_GetFromCache(0, key0);"
17177 " var r1 = %_GetFromCache(0, key1);"
17178 " var r0_ = %_GetFromCache(0, key0);"
17180 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
17181 " var r1_ = %_GetFromCache(0, key1);"
17183 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
17184 " return 'PASSED';"
17186 CcTest::heap()->ClearJSFunctionResultCaches();
17187 ExpectString(code, "PASSED");
17191 THREADED_TEST(FillJSFunctionResultCache) {
17192 i::FLAG_allow_natives_syntax = true;
17193 LocalContext context;
17194 v8::HandleScope scope(context->GetIsolate());
17199 " var r = %_GetFromCache(0, k);"
17200 " for (var i = 0; i < 16; i++) {"
17201 " %_GetFromCache(0, 'a' + i);"
17203 " if (r === %_GetFromCache(0, k))"
17204 " return 'FAILED: k0CacheSize is too small';"
17205 " return 'PASSED';"
17207 CcTest::heap()->ClearJSFunctionResultCaches();
17208 ExpectString(code, "PASSED");
17212 THREADED_TEST(RoundRobinGetFromCache) {
17213 i::FLAG_allow_natives_syntax = true;
17214 LocalContext context;
17215 v8::HandleScope scope(context->GetIsolate());
17220 " for (var i = 0; i < 16; i++) keys.push(i);"
17221 " var values = [];"
17222 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17223 " for (var i = 0; i < 16; i++) {"
17224 " var v = %_GetFromCache(0, keys[i]);"
17225 " if (v.toString() !== values[i].toString())"
17226 " return 'Wrong value for ' + "
17227 " keys[i] + ': ' + v + ' vs. ' + values[i];"
17229 " return 'PASSED';"
17231 CcTest::heap()->ClearJSFunctionResultCaches();
17232 ExpectString(code, "PASSED");
17236 THREADED_TEST(ReverseGetFromCache) {
17237 i::FLAG_allow_natives_syntax = true;
17238 LocalContext context;
17239 v8::HandleScope scope(context->GetIsolate());
17244 " for (var i = 0; i < 16; i++) keys.push(i);"
17245 " var values = [];"
17246 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
17247 " for (var i = 15; i >= 16; i--) {"
17248 " var v = %_GetFromCache(0, keys[i]);"
17249 " if (v !== values[i])"
17250 " return 'Wrong value for ' + "
17251 " keys[i] + ': ' + v + ' vs. ' + values[i];"
17253 " return 'PASSED';"
17255 CcTest::heap()->ClearJSFunctionResultCaches();
17256 ExpectString(code, "PASSED");
17260 THREADED_TEST(TestEviction) {
17261 i::FLAG_allow_natives_syntax = true;
17262 LocalContext context;
17263 v8::HandleScope scope(context->GetIsolate());
17267 " for (var i = 0; i < 2*16; i++) {"
17268 " %_GetFromCache(0, 'a' + i);"
17270 " return 'PASSED';"
17272 CcTest::heap()->ClearJSFunctionResultCaches();
17273 ExpectString(code, "PASSED");
17277 THREADED_TEST(TwoByteStringInOneByteCons) {
17278 // See Chromium issue 47824.
17279 LocalContext context;
17280 v8::HandleScope scope(context->GetIsolate());
17282 const char* init_code =
17283 "var str1 = 'abelspendabel';"
17284 "var str2 = str1 + str1 + str1;"
17286 Local<Value> result = CompileRun(init_code);
17288 Local<Value> indexof = CompileRun("str2.indexOf('els')");
17289 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
17291 CHECK(result->IsString());
17292 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
17293 int length = string->length();
17294 CHECK(string->IsOneByteRepresentation());
17296 i::Handle<i::String> flat_string = i::String::Flatten(string);
17298 CHECK(string->IsOneByteRepresentation());
17299 CHECK(flat_string->IsOneByteRepresentation());
17301 // Create external resource.
17302 uint16_t* uc16_buffer = new uint16_t[length + 1];
17304 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
17305 uc16_buffer[length] = 0;
17307 TestResource resource(uc16_buffer);
17309 flat_string->MakeExternal(&resource);
17311 CHECK(flat_string->IsTwoByteRepresentation());
17313 // If the cons string has been short-circuited, skip the following checks.
17314 if (!string.is_identical_to(flat_string)) {
17315 // At this point, we should have a Cons string which is flat and one-byte,
17316 // with a first half that is a two-byte string (although it only contains
17317 // one-byte characters). This is a valid sequence of steps, and it can
17318 // happen in real pages.
17319 CHECK(string->IsOneByteRepresentation());
17320 i::ConsString* cons = i::ConsString::cast(*string);
17321 CHECK_EQ(0, cons->second()->length());
17322 CHECK(cons->first()->IsTwoByteRepresentation());
17325 // Check that some string operations work.
17328 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
17329 CHECK_EQ(6, reresult->Int32Value());
17332 reresult = CompileRun("str2.match(/abe./g).length;");
17333 CHECK_EQ(6, reresult->Int32Value());
17335 reresult = CompileRun("str2.search(/bel/g);");
17336 CHECK_EQ(1, reresult->Int32Value());
17338 reresult = CompileRun("str2.search(/be./g);");
17339 CHECK_EQ(1, reresult->Int32Value());
17341 ExpectTrue("/bel/g.test(str2);");
17343 ExpectTrue("/be./g.test(str2);");
17345 reresult = CompileRun("/bel/g.exec(str2);");
17346 CHECK(!reresult->IsNull());
17348 reresult = CompileRun("/be./g.exec(str2);");
17349 CHECK(!reresult->IsNull());
17351 ExpectString("str2.substring(2, 10);", "elspenda");
17353 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
17355 ExpectString("str2.charAt(2);", "e");
17357 ExpectObject("str2.indexOf('els');", indexof);
17359 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
17361 reresult = CompileRun("str2.charCodeAt(2);");
17362 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
17366 TEST(ContainsOnlyOneByte) {
17367 v8::V8::Initialize();
17368 v8::Isolate* isolate = CcTest::isolate();
17369 v8::HandleScope scope(isolate);
17370 // Make a buffer long enough that it won't automatically be converted.
17371 const int length = 512;
17372 // Ensure word aligned assignment.
17373 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
17374 i::SmartArrayPointer<uintptr_t>
17375 aligned_contents(new uintptr_t[aligned_length]);
17376 uint16_t* string_contents =
17377 reinterpret_cast<uint16_t*>(aligned_contents.get());
17378 // Set to contain only one byte.
17379 for (int i = 0; i < length-1; i++) {
17380 string_contents[i] = 0x41;
17382 string_contents[length-1] = 0;
17384 Handle<String> string =
17385 String::NewExternal(isolate,
17386 new TestResource(string_contents, NULL, false));
17387 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17388 // Counter example.
17389 string = String::NewFromTwoByte(isolate, string_contents);
17390 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17391 // Test left right and balanced cons strings.
17392 Handle<String> base = String::NewFromUtf8(isolate, "a");
17393 Handle<String> left = base;
17394 Handle<String> right = base;
17395 for (int i = 0; i < 1000; i++) {
17396 left = String::Concat(base, left);
17397 right = String::Concat(right, base);
17399 Handle<String> balanced = String::Concat(left, base);
17400 balanced = String::Concat(balanced, right);
17401 Handle<String> cons_strings[] = {left, balanced, right};
17402 Handle<String> two_byte =
17403 String::NewExternal(isolate,
17404 new TestResource(string_contents, NULL, false));
17405 USE(two_byte); USE(cons_strings);
17406 for (size_t i = 0; i < arraysize(cons_strings); i++) {
17407 // Base assumptions.
17408 string = cons_strings[i];
17409 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
17410 // Test left and right concatentation.
17411 string = String::Concat(two_byte, cons_strings[i]);
17412 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17413 string = String::Concat(cons_strings[i], two_byte);
17414 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
17416 // Set bits in different positions
17417 // for strings of different lengths and alignments.
17418 for (int alignment = 0; alignment < 7; alignment++) {
17419 for (int size = 2; alignment + size < length; size *= 2) {
17420 int zero_offset = size + alignment;
17421 string_contents[zero_offset] = 0;
17422 for (int i = 0; i < size; i++) {
17423 int shift = 8 + (i % 7);
17424 string_contents[alignment + i] = 1 << shift;
17425 string = String::NewExternal(
17427 new TestResource(string_contents + alignment, NULL, false));
17428 CHECK_EQ(size, string->Length());
17429 CHECK(!string->ContainsOnlyOneByte());
17430 string_contents[alignment + i] = 0x41;
17432 string_contents[zero_offset] = 0x41;
17438 // Failed access check callback that performs a GC on each invocation.
17439 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
17440 v8::AccessType type,
17441 Local<v8::Value> data) {
17442 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17446 TEST(GCInFailedAccessCheckCallback) {
17447 // Install a failed access check callback that performs a GC on each
17448 // invocation. Then force the callback to be called from va
17450 v8::V8::Initialize();
17451 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
17453 v8::Isolate* isolate = CcTest::isolate();
17454 v8::HandleScope scope(isolate);
17456 // Create an ObjectTemplate for global objects and install access
17457 // check callbacks that will block access.
17458 v8::Handle<v8::ObjectTemplate> global_template =
17459 v8::ObjectTemplate::New(isolate);
17460 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
17461 IndexedGetAccessBlocker,
17462 v8::Handle<v8::Value>(),
17465 // Create a context and set an x property on it's global object.
17466 LocalContext context0(NULL, global_template);
17467 context0->Global()->Set(v8_str("x"), v8_num(42));
17468 v8::Handle<v8::Object> global0 = context0->Global();
17470 // Create a context with a different security token so that the
17471 // failed access check callback will be called on each access.
17472 LocalContext context1(NULL, global_template);
17473 context1->Global()->Set(v8_str("other"), global0);
17475 // Get property with failed access check.
17476 ExpectUndefined("other.x");
17478 // Get element with failed access check.
17479 ExpectUndefined("other[0]");
17481 // Set property with failed access check.
17482 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
17483 CHECK(result->IsObject());
17485 // Set element with failed access check.
17486 result = CompileRun("other[0] = new Object()");
17487 CHECK(result->IsObject());
17489 // Get property attribute with failed access check.
17490 ExpectFalse("\'x\' in other");
17492 // Get property attribute for element with failed access check.
17493 ExpectFalse("0 in other");
17495 // Delete property.
17496 ExpectFalse("delete other.x");
17499 CHECK_EQ(false, global0->Delete(0));
17503 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
17505 // Define JavaScript accessor.
17506 ExpectUndefined("Object.prototype.__defineGetter__.call("
17507 " other, \'x\', function() { return 42; })");
17510 ExpectUndefined("Object.prototype.__lookupGetter__.call("
17514 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
17516 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
17517 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
17518 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
17520 // Reset the failed access check callback so it does not influence
17521 // the other tests.
17522 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
17526 TEST(IsolateNewDispose) {
17527 v8::Isolate* current_isolate = CcTest::isolate();
17528 v8::Isolate* isolate = v8::Isolate::New();
17529 CHECK(isolate != NULL);
17530 CHECK(current_isolate != isolate);
17531 CHECK(current_isolate == CcTest::isolate());
17533 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17534 last_location = last_message = NULL;
17535 isolate->Dispose();
17536 CHECK(!last_location);
17537 CHECK(!last_message);
17541 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
17542 v8::Isolate* isolate = v8::Isolate::New();
17544 v8::Isolate::Scope i_scope(isolate);
17545 v8::HandleScope scope(isolate);
17546 LocalContext context(isolate);
17547 // Run something in this isolate.
17548 ExpectTrue("true");
17549 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17550 last_location = last_message = NULL;
17551 // Still entered, should fail.
17552 isolate->Dispose();
17553 CHECK(last_location);
17554 CHECK(last_message);
17556 isolate->Dispose();
17560 TEST(RunTwoIsolatesOnSingleThread) {
17562 v8::Isolate* isolate1 = v8::Isolate::New();
17564 v8::Persistent<v8::Context> context1;
17566 v8::HandleScope scope(isolate1);
17567 context1.Reset(isolate1, Context::New(isolate1));
17571 v8::HandleScope scope(isolate1);
17572 v8::Local<v8::Context> context =
17573 v8::Local<v8::Context>::New(isolate1, context1);
17574 v8::Context::Scope context_scope(context);
17575 // Run something in new isolate.
17576 CompileRun("var foo = 'isolate 1';");
17577 ExpectString("function f() { return foo; }; f()", "isolate 1");
17581 v8::Isolate* isolate2 = v8::Isolate::New();
17582 v8::Persistent<v8::Context> context2;
17585 v8::Isolate::Scope iscope(isolate2);
17586 v8::HandleScope scope(isolate2);
17587 context2.Reset(isolate2, Context::New(isolate2));
17588 v8::Local<v8::Context> context =
17589 v8::Local<v8::Context>::New(isolate2, context2);
17590 v8::Context::Scope context_scope(context);
17592 // Run something in new isolate.
17593 CompileRun("var foo = 'isolate 2';");
17594 ExpectString("function f() { return foo; }; f()", "isolate 2");
17598 v8::HandleScope scope(isolate1);
17599 v8::Local<v8::Context> context =
17600 v8::Local<v8::Context>::New(isolate1, context1);
17601 v8::Context::Scope context_scope(context);
17602 // Now again in isolate 1
17603 ExpectString("function f() { return foo; }; f()", "isolate 1");
17608 // Run some stuff in default isolate.
17609 v8::Persistent<v8::Context> context_default;
17611 v8::Isolate* isolate = CcTest::isolate();
17612 v8::Isolate::Scope iscope(isolate);
17613 v8::HandleScope scope(isolate);
17614 context_default.Reset(isolate, Context::New(isolate));
17618 v8::HandleScope scope(CcTest::isolate());
17619 v8::Local<v8::Context> context =
17620 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17621 v8::Context::Scope context_scope(context);
17622 // Variables in other isolates should be not available, verify there
17623 // is an exception.
17624 ExpectTrue("function f() {"
17632 "var isDefaultIsolate = true;"
17639 v8::Isolate::Scope iscope(isolate2);
17640 v8::HandleScope scope(isolate2);
17641 v8::Local<v8::Context> context =
17642 v8::Local<v8::Context>::New(isolate2, context2);
17643 v8::Context::Scope context_scope(context);
17644 ExpectString("function f() { return foo; }; f()", "isolate 2");
17648 v8::HandleScope scope(v8::Isolate::GetCurrent());
17649 v8::Local<v8::Context> context =
17650 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
17651 v8::Context::Scope context_scope(context);
17652 ExpectString("function f() { return foo; }; f()", "isolate 1");
17656 v8::Isolate::Scope iscope(isolate2);
17663 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17664 last_location = last_message = NULL;
17666 isolate1->Dispose();
17667 CHECK(!last_location);
17668 CHECK(!last_message);
17670 isolate2->Dispose();
17671 CHECK(!last_location);
17672 CHECK(!last_message);
17674 // Check that default isolate still runs.
17676 v8::HandleScope scope(CcTest::isolate());
17677 v8::Local<v8::Context> context =
17678 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
17679 v8::Context::Scope context_scope(context);
17680 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
17685 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
17686 v8::Isolate::Scope isolate_scope(isolate);
17687 v8::HandleScope scope(isolate);
17688 LocalContext context(isolate);
17689 i::ScopedVector<char> code(1024);
17690 i::SNPrintF(code, "function fib(n) {"
17691 " if (n <= 2) return 1;"
17692 " return fib(n-1) + fib(n-2);"
17695 Local<Value> value = CompileRun(code.start());
17696 CHECK(value->IsNumber());
17697 return static_cast<int>(value->NumberValue());
17700 class IsolateThread : public v8::base::Thread {
17702 explicit IsolateThread(int fib_limit)
17703 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
17706 v8::Isolate* isolate = v8::Isolate::New();
17707 result_ = CalcFibonacci(isolate, fib_limit_);
17708 isolate->Dispose();
17711 int result() { return result_; }
17719 TEST(MultipleIsolatesOnIndividualThreads) {
17720 IsolateThread thread1(21);
17721 IsolateThread thread2(12);
17723 // Compute some fibonacci numbers on 3 threads in 3 isolates.
17727 int result1 = CalcFibonacci(CcTest::isolate(), 21);
17728 int result2 = CalcFibonacci(CcTest::isolate(), 12);
17733 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
17734 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
17735 CHECK_EQ(result1, 10946);
17736 CHECK_EQ(result2, 144);
17737 CHECK_EQ(result1, thread1.result());
17738 CHECK_EQ(result2, thread2.result());
17742 TEST(IsolateDifferentContexts) {
17743 v8::Isolate* isolate = v8::Isolate::New();
17744 Local<v8::Context> context;
17746 v8::Isolate::Scope isolate_scope(isolate);
17747 v8::HandleScope handle_scope(isolate);
17748 context = v8::Context::New(isolate);
17749 v8::Context::Scope context_scope(context);
17750 Local<Value> v = CompileRun("2");
17751 CHECK(v->IsNumber());
17752 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
17755 v8::Isolate::Scope isolate_scope(isolate);
17756 v8::HandleScope handle_scope(isolate);
17757 context = v8::Context::New(isolate);
17758 v8::Context::Scope context_scope(context);
17759 Local<Value> v = CompileRun("22");
17760 CHECK(v->IsNumber());
17761 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
17763 isolate->Dispose();
17766 class InitDefaultIsolateThread : public v8::base::Thread {
17769 SetResourceConstraints,
17771 SetCounterFunction,
17772 SetCreateHistogramFunction,
17773 SetAddHistogramSampleFunction
17776 explicit InitDefaultIsolateThread(TestCase testCase)
17777 : Thread(Options("InitDefaultIsolateThread")),
17778 testCase_(testCase),
17782 v8::Isolate::CreateParams create_params;
17783 switch (testCase_) {
17784 case SetResourceConstraints: {
17785 create_params.constraints.set_max_semi_space_size(1);
17786 create_params.constraints.set_max_old_space_size(4);
17792 v8::Isolate* isolate = v8::Isolate::New(create_params);
17794 switch (testCase_) {
17795 case SetResourceConstraints:
17796 // Already handled in pre-Isolate-creation block.
17799 case SetFatalHandler:
17800 v8::V8::SetFatalErrorHandler(NULL);
17803 case SetCounterFunction:
17804 CcTest::isolate()->SetCounterFunction(NULL);
17807 case SetCreateHistogramFunction:
17808 CcTest::isolate()->SetCreateHistogramFunction(NULL);
17811 case SetAddHistogramSampleFunction:
17812 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
17816 isolate->Dispose();
17820 bool result() { return result_; }
17823 TestCase testCase_;
17828 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
17829 InitDefaultIsolateThread thread(testCase);
17832 CHECK_EQ(thread.result(), true);
17836 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
17837 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
17841 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
17842 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
17846 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
17847 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
17851 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
17852 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
17856 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
17857 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
17861 TEST(StringCheckMultipleContexts) {
17863 "(function() { return \"a\".charAt(0); })()";
17866 // Run the code twice in the first context to initialize the call IC.
17867 LocalContext context1;
17868 v8::HandleScope scope(context1->GetIsolate());
17869 ExpectString(code, "a");
17870 ExpectString(code, "a");
17874 // Change the String.prototype in the second context and check
17875 // that the right function gets called.
17876 LocalContext context2;
17877 v8::HandleScope scope(context2->GetIsolate());
17878 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
17879 ExpectString(code, "not a");
17884 TEST(NumberCheckMultipleContexts) {
17886 "(function() { return (42).toString(); })()";
17889 // Run the code twice in the first context to initialize the call IC.
17890 LocalContext context1;
17891 v8::HandleScope scope(context1->GetIsolate());
17892 ExpectString(code, "42");
17893 ExpectString(code, "42");
17897 // Change the Number.prototype in the second context and check
17898 // that the right function gets called.
17899 LocalContext context2;
17900 v8::HandleScope scope(context2->GetIsolate());
17901 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
17902 ExpectString(code, "not 42");
17907 TEST(BooleanCheckMultipleContexts) {
17909 "(function() { return true.toString(); })()";
17912 // Run the code twice in the first context to initialize the call IC.
17913 LocalContext context1;
17914 v8::HandleScope scope(context1->GetIsolate());
17915 ExpectString(code, "true");
17916 ExpectString(code, "true");
17920 // Change the Boolean.prototype in the second context and check
17921 // that the right function gets called.
17922 LocalContext context2;
17923 v8::HandleScope scope(context2->GetIsolate());
17924 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
17925 ExpectString(code, "");
17930 TEST(DontDeleteCellLoadIC) {
17931 const char* function_code =
17932 "function readCell() { while (true) { return cell; } }";
17935 // Run the code twice in the first context to initialize the load
17936 // IC for a don't delete cell.
17937 LocalContext context1;
17938 v8::HandleScope scope(context1->GetIsolate());
17939 CompileRun("var cell = \"first\";");
17940 ExpectBoolean("delete cell", false);
17941 CompileRun(function_code);
17942 ExpectString("readCell()", "first");
17943 ExpectString("readCell()", "first");
17947 // Use a deletable cell in the second context.
17948 LocalContext context2;
17949 v8::HandleScope scope(context2->GetIsolate());
17950 CompileRun("cell = \"second\";");
17951 CompileRun(function_code);
17952 ExpectString("readCell()", "second");
17953 ExpectBoolean("delete cell", true);
17954 ExpectString("(function() {"
17956 " return readCell();"
17958 " return e.toString();"
17961 "ReferenceError: cell is not defined");
17962 CompileRun("cell = \"new_second\";");
17963 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17964 ExpectString("readCell()", "new_second");
17965 ExpectString("readCell()", "new_second");
17970 class Visitor42 : public v8::PersistentHandleVisitor {
17972 explicit Visitor42(v8::Persistent<v8::Object>* object)
17973 : counter_(0), object_(object) { }
17975 virtual void VisitPersistentHandle(Persistent<Value>* value,
17976 uint16_t class_id) {
17977 if (class_id != 42) return;
17978 CHECK_EQ(42, value->WrapperClassId());
17979 v8::Isolate* isolate = CcTest::isolate();
17980 v8::HandleScope handle_scope(isolate);
17981 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
17982 v8::Handle<v8::Value> object =
17983 v8::Local<v8::Object>::New(isolate, *object_);
17984 CHECK(handle->IsObject());
17985 CHECK(Handle<Object>::Cast(handle)->Equals(object));
17990 v8::Persistent<v8::Object>* object_;
17994 TEST(PersistentHandleVisitor) {
17995 LocalContext context;
17996 v8::Isolate* isolate = context->GetIsolate();
17997 v8::HandleScope scope(isolate);
17998 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
17999 CHECK_EQ(0, object.WrapperClassId());
18000 object.SetWrapperClassId(42);
18001 CHECK_EQ(42, object.WrapperClassId());
18003 Visitor42 visitor(&object);
18004 v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
18005 CHECK_EQ(1, visitor.counter_);
18011 TEST(WrapperClassId) {
18012 LocalContext context;
18013 v8::Isolate* isolate = context->GetIsolate();
18014 v8::HandleScope scope(isolate);
18015 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
18016 CHECK_EQ(0, object.WrapperClassId());
18017 object.SetWrapperClassId(65535);
18018 CHECK_EQ(65535, object.WrapperClassId());
18023 TEST(PersistentHandleInNewSpaceVisitor) {
18024 LocalContext context;
18025 v8::Isolate* isolate = context->GetIsolate();
18026 v8::HandleScope scope(isolate);
18027 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
18028 CHECK_EQ(0, object1.WrapperClassId());
18029 object1.SetWrapperClassId(42);
18030 CHECK_EQ(42, object1.WrapperClassId());
18032 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18033 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
18035 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
18036 CHECK_EQ(0, object2.WrapperClassId());
18037 object2.SetWrapperClassId(42);
18038 CHECK_EQ(42, object2.WrapperClassId());
18040 Visitor42 visitor(&object2);
18041 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
18042 CHECK_EQ(1, visitor.counter_);
18050 LocalContext context;
18051 v8::HandleScope scope(context->GetIsolate());
18053 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
18054 CHECK(re->IsRegExp());
18055 CHECK(re->GetSource()->Equals(v8_str("foo")));
18056 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18058 re = v8::RegExp::New(v8_str("bar"),
18059 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18060 v8::RegExp::kGlobal));
18061 CHECK(re->IsRegExp());
18062 CHECK(re->GetSource()->Equals(v8_str("bar")));
18063 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
18064 static_cast<int>(re->GetFlags()));
18066 re = v8::RegExp::New(v8_str("baz"),
18067 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18068 v8::RegExp::kMultiline));
18069 CHECK(re->IsRegExp());
18070 CHECK(re->GetSource()->Equals(v8_str("baz")));
18071 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18072 static_cast<int>(re->GetFlags()));
18074 re = CompileRun("/quux/").As<v8::RegExp>();
18075 CHECK(re->IsRegExp());
18076 CHECK(re->GetSource()->Equals(v8_str("quux")));
18077 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18079 re = CompileRun("/quux/gm").As<v8::RegExp>();
18080 CHECK(re->IsRegExp());
18081 CHECK(re->GetSource()->Equals(v8_str("quux")));
18082 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
18083 static_cast<int>(re->GetFlags()));
18085 // Override the RegExp constructor and check the API constructor
18087 CompileRun("RegExp = function() {}");
18089 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
18090 CHECK(re->IsRegExp());
18091 CHECK(re->GetSource()->Equals(v8_str("foobar")));
18092 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
18094 re = v8::RegExp::New(v8_str("foobarbaz"),
18095 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
18096 v8::RegExp::kMultiline));
18097 CHECK(re->IsRegExp());
18098 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
18099 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
18100 static_cast<int>(re->GetFlags()));
18102 context->Global()->Set(v8_str("re"), re);
18103 ExpectTrue("re.test('FoobarbaZ')");
18105 // RegExps are objects on which you can set properties.
18106 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
18107 v8::Handle<v8::Value> value(CompileRun("re.property"));
18108 CHECK_EQ(32, value->Int32Value());
18110 v8::TryCatch try_catch;
18111 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
18112 CHECK(re.IsEmpty());
18113 CHECK(try_catch.HasCaught());
18114 context->Global()->Set(v8_str("ex"), try_catch.Exception());
18115 ExpectTrue("ex instanceof SyntaxError");
18119 THREADED_TEST(Equals) {
18120 LocalContext localContext;
18121 v8::HandleScope handleScope(localContext->GetIsolate());
18123 v8::Handle<v8::Object> globalProxy = localContext->Global();
18124 v8::Handle<Value> global = globalProxy->GetPrototype();
18126 CHECK(global->StrictEquals(global));
18127 CHECK(!global->StrictEquals(globalProxy));
18128 CHECK(!globalProxy->StrictEquals(global));
18129 CHECK(globalProxy->StrictEquals(globalProxy));
18131 CHECK(global->Equals(global));
18132 CHECK(!global->Equals(globalProxy));
18133 CHECK(!globalProxy->Equals(global));
18134 CHECK(globalProxy->Equals(globalProxy));
18138 static void Getter(v8::Local<v8::Name> property,
18139 const v8::PropertyCallbackInfo<v8::Value>& info) {
18140 info.GetReturnValue().Set(v8_str("42!"));
18144 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
18145 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
18146 result->Set(0, v8_str("universalAnswer"));
18147 info.GetReturnValue().Set(result);
18151 TEST(NamedEnumeratorAndForIn) {
18152 LocalContext context;
18153 v8::Isolate* isolate = context->GetIsolate();
18154 v8::HandleScope handle_scope(isolate);
18155 v8::Context::Scope context_scope(context.local());
18157 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
18158 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
18159 NULL, Enumerator));
18160 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
18161 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
18162 "var result = []; for (var k in o) result.push(k); result"));
18163 CHECK_EQ(1u, result->Length());
18164 CHECK(v8_str("universalAnswer")->Equals(result->Get(0)));
18168 TEST(DefinePropertyPostDetach) {
18169 LocalContext context;
18170 v8::HandleScope scope(context->GetIsolate());
18171 v8::Handle<v8::Object> proxy = context->Global();
18172 v8::Handle<v8::Function> define_property =
18173 CompileRun("(function() {"
18174 " Object.defineProperty("
18177 " { configurable: true, enumerable: true, value: 3 });"
18178 "})").As<Function>();
18179 context->DetachGlobal();
18180 define_property->Call(proxy, 0, NULL);
18184 static void InstallContextId(v8::Handle<Context> context, int id) {
18185 Context::Scope scope(context);
18186 CompileRun("Object.prototype").As<Object>()->
18187 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
18191 static void CheckContextId(v8::Handle<Object> object, int expected) {
18192 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
18196 THREADED_TEST(CreationContext) {
18197 v8::Isolate* isolate = CcTest::isolate();
18198 HandleScope handle_scope(isolate);
18199 Handle<Context> context1 = Context::New(isolate);
18200 InstallContextId(context1, 1);
18201 Handle<Context> context2 = Context::New(isolate);
18202 InstallContextId(context2, 2);
18203 Handle<Context> context3 = Context::New(isolate);
18204 InstallContextId(context3, 3);
18206 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
18208 Local<Object> object1;
18209 Local<Function> func1;
18211 Context::Scope scope(context1);
18212 object1 = Object::New(isolate);
18213 func1 = tmpl->GetFunction();
18216 Local<Object> object2;
18217 Local<Function> func2;
18219 Context::Scope scope(context2);
18220 object2 = Object::New(isolate);
18221 func2 = tmpl->GetFunction();
18224 Local<Object> instance1;
18225 Local<Object> instance2;
18228 Context::Scope scope(context3);
18229 instance1 = func1->NewInstance();
18230 instance2 = func2->NewInstance();
18233 CHECK(object1->CreationContext() == context1);
18234 CheckContextId(object1, 1);
18235 CHECK(func1->CreationContext() == context1);
18236 CheckContextId(func1, 1);
18237 CHECK(instance1->CreationContext() == context1);
18238 CheckContextId(instance1, 1);
18239 CHECK(object2->CreationContext() == context2);
18240 CheckContextId(object2, 2);
18241 CHECK(func2->CreationContext() == context2);
18242 CheckContextId(func2, 2);
18243 CHECK(instance2->CreationContext() == context2);
18244 CheckContextId(instance2, 2);
18247 Context::Scope scope(context1);
18248 CHECK(object1->CreationContext() == context1);
18249 CheckContextId(object1, 1);
18250 CHECK(func1->CreationContext() == context1);
18251 CheckContextId(func1, 1);
18252 CHECK(instance1->CreationContext() == context1);
18253 CheckContextId(instance1, 1);
18254 CHECK(object2->CreationContext() == context2);
18255 CheckContextId(object2, 2);
18256 CHECK(func2->CreationContext() == context2);
18257 CheckContextId(func2, 2);
18258 CHECK(instance2->CreationContext() == context2);
18259 CheckContextId(instance2, 2);
18263 Context::Scope scope(context2);
18264 CHECK(object1->CreationContext() == context1);
18265 CheckContextId(object1, 1);
18266 CHECK(func1->CreationContext() == context1);
18267 CheckContextId(func1, 1);
18268 CHECK(instance1->CreationContext() == context1);
18269 CheckContextId(instance1, 1);
18270 CHECK(object2->CreationContext() == context2);
18271 CheckContextId(object2, 2);
18272 CHECK(func2->CreationContext() == context2);
18273 CheckContextId(func2, 2);
18274 CHECK(instance2->CreationContext() == context2);
18275 CheckContextId(instance2, 2);
18280 THREADED_TEST(CreationContextOfJsFunction) {
18281 HandleScope handle_scope(CcTest::isolate());
18282 Handle<Context> context = Context::New(CcTest::isolate());
18283 InstallContextId(context, 1);
18285 Local<Object> function;
18287 Context::Scope scope(context);
18288 function = CompileRun("function foo() {}; foo").As<Object>();
18291 CHECK(function->CreationContext() == context);
18292 CheckContextId(function, 1);
18296 void HasOwnPropertyIndexedPropertyGetter(
18298 const v8::PropertyCallbackInfo<v8::Value>& info) {
18299 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
18303 void HasOwnPropertyNamedPropertyGetter(
18304 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
18305 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
18309 void HasOwnPropertyIndexedPropertyQuery(
18310 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18311 if (index == 42) info.GetReturnValue().Set(1);
18315 void HasOwnPropertyNamedPropertyQuery(
18316 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18317 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
18321 void HasOwnPropertyNamedPropertyQuery2(
18322 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
18323 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
18327 void HasOwnPropertyAccessorGetter(
18328 Local<String> property,
18329 const v8::PropertyCallbackInfo<v8::Value>& info) {
18330 info.GetReturnValue().Set(v8_str("yes"));
18334 TEST(HasOwnProperty) {
18336 v8::Isolate* isolate = env->GetIsolate();
18337 v8::HandleScope scope(isolate);
18338 { // Check normal properties and defined getters.
18339 Handle<Value> value = CompileRun(
18342 " this.__defineGetter__('baz', function() { return 1; });"
18344 "function Bar() { "
18346 " this.__defineGetter__('bla', function() { return 2; });"
18348 "Bar.prototype = new Foo();"
18350 CHECK(value->IsObject());
18351 Handle<Object> object = value->ToObject(isolate);
18352 CHECK(object->Has(v8_str("foo")));
18353 CHECK(!object->HasOwnProperty(v8_str("foo")));
18354 CHECK(object->HasOwnProperty(v8_str("bar")));
18355 CHECK(object->Has(v8_str("baz")));
18356 CHECK(!object->HasOwnProperty(v8_str("baz")));
18357 CHECK(object->HasOwnProperty(v8_str("bla")));
18359 { // Check named getter interceptors.
18360 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18361 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
18362 HasOwnPropertyNamedPropertyGetter));
18363 Handle<Object> instance = templ->NewInstance();
18364 CHECK(!instance->HasOwnProperty(v8_str("42")));
18365 CHECK(instance->HasOwnProperty(v8_str("foo")));
18366 CHECK(!instance->HasOwnProperty(v8_str("bar")));
18368 { // Check indexed getter interceptors.
18369 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18370 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
18371 HasOwnPropertyIndexedPropertyGetter));
18372 Handle<Object> instance = templ->NewInstance();
18373 CHECK(instance->HasOwnProperty(v8_str("42")));
18374 CHECK(!instance->HasOwnProperty(v8_str("43")));
18375 CHECK(!instance->HasOwnProperty(v8_str("foo")));
18377 { // Check named query interceptors.
18378 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18379 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
18380 0, 0, HasOwnPropertyNamedPropertyQuery));
18381 Handle<Object> instance = templ->NewInstance();
18382 CHECK(instance->HasOwnProperty(v8_str("foo")));
18383 CHECK(!instance->HasOwnProperty(v8_str("bar")));
18385 { // Check indexed query interceptors.
18386 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18387 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
18388 0, 0, HasOwnPropertyIndexedPropertyQuery));
18389 Handle<Object> instance = templ->NewInstance();
18390 CHECK(instance->HasOwnProperty(v8_str("42")));
18391 CHECK(!instance->HasOwnProperty(v8_str("41")));
18393 { // Check callbacks.
18394 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18395 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
18396 Handle<Object> instance = templ->NewInstance();
18397 CHECK(instance->HasOwnProperty(v8_str("foo")));
18398 CHECK(!instance->HasOwnProperty(v8_str("bar")));
18400 { // Check that query wins on disagreement.
18401 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18402 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
18403 HasOwnPropertyNamedPropertyGetter, 0,
18404 HasOwnPropertyNamedPropertyQuery2));
18405 Handle<Object> instance = templ->NewInstance();
18406 CHECK(!instance->HasOwnProperty(v8_str("foo")));
18407 CHECK(instance->HasOwnProperty(v8_str("bar")));
18412 TEST(IndexedInterceptorWithStringProto) {
18413 v8::Isolate* isolate = CcTest::isolate();
18414 v8::HandleScope scope(isolate);
18415 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18416 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
18417 NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
18418 LocalContext context;
18419 context->Global()->Set(v8_str("obj"), templ->NewInstance());
18420 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
18421 // These should be intercepted.
18422 CHECK(CompileRun("42 in obj")->BooleanValue());
18423 CHECK(CompileRun("'42' in obj")->BooleanValue());
18424 // These should fall through to the String prototype.
18425 CHECK(CompileRun("0 in obj")->BooleanValue());
18426 CHECK(CompileRun("'0' in obj")->BooleanValue());
18427 // And these should both fail.
18428 CHECK(!CompileRun("32 in obj")->BooleanValue());
18429 CHECK(!CompileRun("'32' in obj")->BooleanValue());
18433 void CheckCodeGenerationAllowed() {
18434 Handle<Value> result = CompileRun("eval('42')");
18435 CHECK_EQ(42, result->Int32Value());
18436 result = CompileRun("(function(e) { return e('42'); })(eval)");
18437 CHECK_EQ(42, result->Int32Value());
18438 result = CompileRun("var f = new Function('return 42'); f()");
18439 CHECK_EQ(42, result->Int32Value());
18443 void CheckCodeGenerationDisallowed() {
18444 TryCatch try_catch;
18446 Handle<Value> result = CompileRun("eval('42')");
18447 CHECK(result.IsEmpty());
18448 CHECK(try_catch.HasCaught());
18451 result = CompileRun("(function(e) { return e('42'); })(eval)");
18452 CHECK(result.IsEmpty());
18453 CHECK(try_catch.HasCaught());
18456 result = CompileRun("var f = new Function('return 42'); f()");
18457 CHECK(result.IsEmpty());
18458 CHECK(try_catch.HasCaught());
18462 bool CodeGenerationAllowed(Local<Context> context) {
18463 ApiTestFuzzer::Fuzz();
18468 bool CodeGenerationDisallowed(Local<Context> context) {
18469 ApiTestFuzzer::Fuzz();
18474 THREADED_TEST(AllowCodeGenFromStrings) {
18475 LocalContext context;
18476 v8::HandleScope scope(context->GetIsolate());
18478 // eval and the Function constructor allowed by default.
18479 CHECK(context->IsCodeGenerationFromStringsAllowed());
18480 CheckCodeGenerationAllowed();
18482 // Disallow eval and the Function constructor.
18483 context->AllowCodeGenerationFromStrings(false);
18484 CHECK(!context->IsCodeGenerationFromStringsAllowed());
18485 CheckCodeGenerationDisallowed();
18488 context->AllowCodeGenerationFromStrings(true);
18489 CheckCodeGenerationAllowed();
18491 // Disallow but setting a global callback that will allow the calls.
18492 context->AllowCodeGenerationFromStrings(false);
18493 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
18494 CHECK(!context->IsCodeGenerationFromStringsAllowed());
18495 CheckCodeGenerationAllowed();
18497 // Set a callback that disallows the code generation.
18498 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
18499 CHECK(!context->IsCodeGenerationFromStringsAllowed());
18500 CheckCodeGenerationDisallowed();
18504 TEST(SetErrorMessageForCodeGenFromStrings) {
18505 LocalContext context;
18506 v8::HandleScope scope(context->GetIsolate());
18507 TryCatch try_catch;
18509 Handle<String> message = v8_str("Message") ;
18510 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
18511 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
18512 context->AllowCodeGenerationFromStrings(false);
18513 context->SetErrorMessageForCodeGenerationFromStrings(message);
18514 Handle<Value> result = CompileRun("eval('42')");
18515 CHECK(result.IsEmpty());
18516 CHECK(try_catch.HasCaught());
18517 Handle<String> actual_message = try_catch.Message()->Get();
18518 CHECK(expected_message->Equals(actual_message));
18522 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
18526 THREADED_TEST(CallAPIFunctionOnNonObject) {
18527 LocalContext context;
18528 v8::Isolate* isolate = context->GetIsolate();
18529 v8::HandleScope scope(isolate);
18530 Handle<FunctionTemplate> templ =
18531 v8::FunctionTemplate::New(isolate, NonObjectThis);
18532 Handle<Function> function = templ->GetFunction();
18533 context->Global()->Set(v8_str("f"), function);
18534 TryCatch try_catch;
18535 CompileRun("f.call(2)");
18539 // Regression test for issue 1470.
18540 THREADED_TEST(ReadOnlyIndexedProperties) {
18541 v8::Isolate* isolate = CcTest::isolate();
18542 v8::HandleScope scope(isolate);
18543 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18545 LocalContext context;
18546 Local<v8::Object> obj = templ->NewInstance();
18547 context->Global()->Set(v8_str("obj"), obj);
18548 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18549 obj->Set(v8_str("1"), v8_str("foobar"));
18550 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("1"))));
18551 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
18552 obj->Set(v8_num(2), v8_str("foobar"));
18553 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_num(2))));
18555 // Test non-smi case.
18556 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
18557 obj->Set(v8_str("2000000000"), v8_str("foobar"));
18558 CHECK(v8_str("DONT_CHANGE")->Equals(obj->Get(v8_str("2000000000"))));
18562 static int CountLiveMapsInMapCache(i::Context* context) {
18563 i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
18564 int length = map_cache->length();
18566 for (int i = 0; i < length; i++) {
18567 i::Object* value = map_cache->get(i);
18568 if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
18574 THREADED_TEST(Regress1516) {
18575 LocalContext context;
18576 v8::HandleScope scope(context->GetIsolate());
18578 // Object with 20 properties is not a common case, so it should be removed
18579 // from the cache after GC.
18580 { v8::HandleScope temp_scope(context->GetIsolate());
18583 "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
18584 "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
18585 "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
18586 "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
18590 int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
18591 CHECK_LE(1, elements);
18593 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
18595 CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
18599 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
18601 v8::AccessType type,
18602 Local<Value> data) {
18603 // Only block read access to __proto__.
18604 if (type == v8::ACCESS_GET && name->IsString() &&
18605 name.As<v8::String>()->Length() == 9 &&
18606 name.As<v8::String>()->Utf8Length() == 9) {
18608 CHECK_EQ(10, name.As<v8::String>()->WriteUtf8(buffer));
18609 return strncmp(buffer, "__proto__", 9) != 0;
18616 THREADED_TEST(Regress93759) {
18617 v8::Isolate* isolate = CcTest::isolate();
18618 HandleScope scope(isolate);
18620 // Template for object with security check.
18621 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
18622 // We don't do indexing, so any callback can be used for that.
18623 no_proto_template->SetAccessCheckCallbacks(
18624 BlockProtoNamedSecurityTestCallback,
18625 IndexedSecurityTestCallback);
18627 // Templates for objects with hidden prototypes and possibly security check.
18628 Local<FunctionTemplate> hidden_proto_template =
18629 v8::FunctionTemplate::New(isolate);
18630 hidden_proto_template->SetHiddenPrototype(true);
18632 Local<FunctionTemplate> protected_hidden_proto_template =
18633 v8::FunctionTemplate::New(isolate);
18634 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
18635 BlockProtoNamedSecurityTestCallback,
18636 IndexedSecurityTestCallback);
18637 protected_hidden_proto_template->SetHiddenPrototype(true);
18639 // Context for "foreign" objects used in test.
18640 Local<Context> context = v8::Context::New(isolate);
18643 // Plain object, no security check.
18644 Local<Object> simple_object = Object::New(isolate);
18646 // Object with explicit security check.
18647 Local<Object> protected_object =
18648 no_proto_template->NewInstance();
18650 // JSGlobalProxy object, always have security check.
18651 Local<Object> proxy_object =
18654 // Global object, the prototype of proxy_object. No security checks.
18655 Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
18657 // Hidden prototype without security check.
18658 Local<Object> hidden_prototype =
18659 hidden_proto_template->GetFunction()->NewInstance();
18660 Local<Object> object_with_hidden =
18661 Object::New(isolate);
18662 object_with_hidden->SetPrototype(hidden_prototype);
18664 // Hidden prototype with security check on the hidden prototype.
18665 Local<Object> protected_hidden_prototype =
18666 protected_hidden_proto_template->GetFunction()->NewInstance();
18667 Local<Object> object_with_protected_hidden =
18668 Object::New(isolate);
18669 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
18673 // Template for object for second context. Values to test are put on it as
18675 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
18676 global_template->Set(v8_str("simple"), simple_object);
18677 global_template->Set(v8_str("protected"), protected_object);
18678 global_template->Set(v8_str("global"), global_object);
18679 global_template->Set(v8_str("proxy"), proxy_object);
18680 global_template->Set(v8_str("hidden"), object_with_hidden);
18681 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
18683 LocalContext context2(NULL, global_template);
18685 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
18686 CHECK(result1->Equals(simple_object->GetPrototype()));
18688 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
18689 CHECK(result2.IsEmpty());
18691 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
18692 CHECK(result3->Equals(global_object->GetPrototype()));
18694 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
18695 CHECK(result4.IsEmpty());
18697 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
18698 CHECK(result5->Equals(
18699 object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
18701 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
18702 CHECK(result6.IsEmpty());
18706 static void TestReceiver(Local<Value> expected_result,
18707 Local<Value> expected_receiver,
18708 const char* code) {
18709 Local<Value> result = CompileRun(code);
18710 CHECK(result->IsObject());
18711 CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
18712 CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
18716 THREADED_TEST(ForeignFunctionReceiver) {
18717 v8::Isolate* isolate = CcTest::isolate();
18718 HandleScope scope(isolate);
18720 // Create two contexts with different "id" properties ('i' and 'o').
18721 // Call a function both from its own context and from a the foreign
18722 // context, and see what "this" is bound to (returning both "this"
18723 // and "this.id" for comparison).
18725 Local<Context> foreign_context = v8::Context::New(isolate);
18726 foreign_context->Enter();
18727 Local<Value> foreign_function =
18728 CompileRun("function func() { return { 0: this.id, "
18730 " toString: function() { "
18737 CHECK(foreign_function->IsFunction());
18738 foreign_context->Exit();
18740 LocalContext context;
18742 Local<String> password = v8_str("Password");
18743 // Don't get hit by security checks when accessing foreign_context's
18744 // global receiver (aka. global proxy).
18745 context->SetSecurityToken(password);
18746 foreign_context->SetSecurityToken(password);
18748 Local<String> i = v8_str("i");
18749 Local<String> o = v8_str("o");
18750 Local<String> id = v8_str("id");
18752 CompileRun("function ownfunc() { return { 0: this.id, "
18754 " toString: function() { "
18761 context->Global()->Set(v8_str("func"), foreign_function);
18763 // Sanity check the contexts.
18764 CHECK(i->Equals(foreign_context->Global()->Get(id)));
18765 CHECK(o->Equals(context->Global()->Get(id)));
18767 // Checking local function's receiver.
18768 // Calling function using its call/apply methods.
18769 TestReceiver(o, context->Global(), "ownfunc.call()");
18770 TestReceiver(o, context->Global(), "ownfunc.apply()");
18771 // Making calls through built-in functions.
18772 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
18773 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
18774 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
18775 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
18776 // Calling with environment record as base.
18777 TestReceiver(o, context->Global(), "ownfunc()");
18778 // Calling with no base.
18779 TestReceiver(o, context->Global(), "(1,ownfunc)()");
18781 // Checking foreign function return value.
18782 // Calling function using its call/apply methods.
18783 TestReceiver(i, foreign_context->Global(), "func.call()");
18784 TestReceiver(i, foreign_context->Global(), "func.apply()");
18785 // Calling function using another context's call/apply methods.
18786 TestReceiver(i, foreign_context->Global(),
18787 "Function.prototype.call.call(func)");
18788 TestReceiver(i, foreign_context->Global(),
18789 "Function.prototype.call.apply(func)");
18790 TestReceiver(i, foreign_context->Global(),
18791 "Function.prototype.apply.call(func)");
18792 TestReceiver(i, foreign_context->Global(),
18793 "Function.prototype.apply.apply(func)");
18794 // Making calls through built-in functions.
18795 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
18796 // ToString(func()) is func()[0], i.e., the returned this.id.
18797 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
18798 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
18799 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
18801 // Calling with environment record as base.
18802 TestReceiver(i, foreign_context->Global(), "func()");
18803 // Calling with no base.
18804 TestReceiver(i, foreign_context->Global(), "(1,func)()");
18808 uint8_t callback_fired = 0;
18811 void CallCompletedCallback1() {
18812 v8::base::OS::Print("Firing callback 1.\n");
18813 callback_fired ^= 1; // Toggle first bit.
18817 void CallCompletedCallback2() {
18818 v8::base::OS::Print("Firing callback 2.\n");
18819 callback_fired ^= 2; // Toggle second bit.
18823 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
18824 int32_t level = args[0]->Int32Value();
18827 v8::base::OS::Print("Entering recursion level %d.\n", level);
18829 i::Vector<char> script_vector(script, sizeof(script));
18830 i::SNPrintF(script_vector, "recursion(%d)", level);
18831 CompileRun(script_vector.start());
18832 v8::base::OS::Print("Leaving recursion level %d.\n", level);
18833 CHECK_EQ(0, callback_fired);
18835 v8::base::OS::Print("Recursion ends.\n");
18836 CHECK_EQ(0, callback_fired);
18841 TEST(CallCompletedCallback) {
18843 v8::HandleScope scope(env->GetIsolate());
18844 v8::Handle<v8::FunctionTemplate> recursive_runtime =
18845 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
18846 env->Global()->Set(v8_str("recursion"),
18847 recursive_runtime->GetFunction());
18848 // Adding the same callback a second time has no effect.
18849 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18850 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
18851 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
18852 v8::base::OS::Print("--- Script (1) ---\n");
18853 Local<Script> script = v8::Script::Compile(
18854 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
18856 CHECK_EQ(3, callback_fired);
18858 v8::base::OS::Print("\n--- Script (2) ---\n");
18859 callback_fired = 0;
18860 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
18862 CHECK_EQ(2, callback_fired);
18864 v8::base::OS::Print("\n--- Function ---\n");
18865 callback_fired = 0;
18866 Local<Function> recursive_function =
18867 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
18868 v8::Handle<Value> args[] = { v8_num(0) };
18869 recursive_function->Call(env->Global(), 1, args);
18870 CHECK_EQ(2, callback_fired);
18874 void CallCompletedCallbackNoException() {
18875 v8::HandleScope scope(CcTest::isolate());
18876 CompileRun("1+1;");
18880 void CallCompletedCallbackException() {
18881 v8::HandleScope scope(CcTest::isolate());
18882 CompileRun("throw 'second exception';");
18886 TEST(CallCompletedCallbackOneException) {
18888 v8::HandleScope scope(env->GetIsolate());
18889 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
18890 CompileRun("throw 'exception';");
18894 TEST(CallCompletedCallbackTwoExceptions) {
18896 v8::HandleScope scope(env->GetIsolate());
18897 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
18898 CompileRun("throw 'first exception';");
18902 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
18903 v8::HandleScope scope(info.GetIsolate());
18904 CompileRun("ext1Calls++;");
18908 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
18909 v8::HandleScope scope(info.GetIsolate());
18910 CompileRun("ext2Calls++;");
18914 void* g_passed_to_three = NULL;
18917 static void MicrotaskThree(void* data) {
18918 g_passed_to_three = data;
18922 TEST(EnqueueMicrotask) {
18924 v8::HandleScope scope(env->GetIsolate());
18926 "var ext1Calls = 0;"
18927 "var ext2Calls = 0;");
18928 CompileRun("1+1;");
18929 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
18930 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18932 env->GetIsolate()->EnqueueMicrotask(
18933 Function::New(env->GetIsolate(), MicrotaskOne));
18934 CompileRun("1+1;");
18935 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
18936 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
18938 env->GetIsolate()->EnqueueMicrotask(
18939 Function::New(env->GetIsolate(), MicrotaskOne));
18940 env->GetIsolate()->EnqueueMicrotask(
18941 Function::New(env->GetIsolate(), MicrotaskTwo));
18942 CompileRun("1+1;");
18943 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18944 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
18946 env->GetIsolate()->EnqueueMicrotask(
18947 Function::New(env->GetIsolate(), MicrotaskTwo));
18948 CompileRun("1+1;");
18949 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18950 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18952 CompileRun("1+1;");
18953 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18954 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18956 g_passed_to_three = NULL;
18957 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
18958 CompileRun("1+1;");
18959 CHECK(!g_passed_to_three);
18960 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
18961 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
18964 env->GetIsolate()->EnqueueMicrotask(
18965 Function::New(env->GetIsolate(), MicrotaskOne));
18966 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
18967 env->GetIsolate()->EnqueueMicrotask(
18968 Function::New(env->GetIsolate(), MicrotaskTwo));
18969 CompileRun("1+1;");
18970 CHECK_EQ(&dummy, g_passed_to_three);
18971 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
18972 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
18973 g_passed_to_three = NULL;
18977 static void MicrotaskExceptionOne(
18978 const v8::FunctionCallbackInfo<Value>& info) {
18979 v8::HandleScope scope(info.GetIsolate());
18980 CompileRun("exception1Calls++;");
18981 info.GetIsolate()->ThrowException(
18982 v8::Exception::Error(v8_str("first")));
18986 static void MicrotaskExceptionTwo(
18987 const v8::FunctionCallbackInfo<Value>& info) {
18988 v8::HandleScope scope(info.GetIsolate());
18989 CompileRun("exception2Calls++;");
18990 info.GetIsolate()->ThrowException(
18991 v8::Exception::Error(v8_str("second")));
18995 TEST(RunMicrotasksIgnoresThrownExceptions) {
18997 v8::Isolate* isolate = env->GetIsolate();
18998 v8::HandleScope scope(isolate);
19000 "var exception1Calls = 0;"
19001 "var exception2Calls = 0;");
19002 isolate->EnqueueMicrotask(
19003 Function::New(isolate, MicrotaskExceptionOne));
19004 isolate->EnqueueMicrotask(
19005 Function::New(isolate, MicrotaskExceptionTwo));
19006 TryCatch try_catch;
19007 CompileRun("1+1;");
19008 CHECK(!try_catch.HasCaught());
19009 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
19010 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
19014 TEST(SetAutorunMicrotasks) {
19016 v8::HandleScope scope(env->GetIsolate());
19018 "var ext1Calls = 0;"
19019 "var ext2Calls = 0;");
19020 CompileRun("1+1;");
19021 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
19022 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
19024 env->GetIsolate()->EnqueueMicrotask(
19025 Function::New(env->GetIsolate(), MicrotaskOne));
19026 CompileRun("1+1;");
19027 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
19028 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
19030 env->GetIsolate()->SetAutorunMicrotasks(false);
19031 env->GetIsolate()->EnqueueMicrotask(
19032 Function::New(env->GetIsolate(), MicrotaskOne));
19033 env->GetIsolate()->EnqueueMicrotask(
19034 Function::New(env->GetIsolate(), MicrotaskTwo));
19035 CompileRun("1+1;");
19036 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
19037 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
19039 env->GetIsolate()->RunMicrotasks();
19040 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19041 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
19043 env->GetIsolate()->EnqueueMicrotask(
19044 Function::New(env->GetIsolate(), MicrotaskTwo));
19045 CompileRun("1+1;");
19046 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19047 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
19049 env->GetIsolate()->RunMicrotasks();
19050 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19051 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
19053 env->GetIsolate()->SetAutorunMicrotasks(true);
19054 env->GetIsolate()->EnqueueMicrotask(
19055 Function::New(env->GetIsolate(), MicrotaskTwo));
19056 CompileRun("1+1;");
19057 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19058 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
19060 env->GetIsolate()->EnqueueMicrotask(
19061 Function::New(env->GetIsolate(), MicrotaskTwo));
19063 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
19064 CompileRun("1+1;");
19065 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19066 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
19069 CompileRun("1+1;");
19070 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
19071 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
19075 TEST(RunMicrotasksWithoutEnteringContext) {
19076 v8::Isolate* isolate = CcTest::isolate();
19077 HandleScope handle_scope(isolate);
19078 isolate->SetAutorunMicrotasks(false);
19079 Handle<Context> context = Context::New(isolate);
19081 Context::Scope context_scope(context);
19082 CompileRun("var ext1Calls = 0;");
19083 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
19085 isolate->RunMicrotasks();
19087 Context::Scope context_scope(context);
19088 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
19090 isolate->SetAutorunMicrotasks(true);
19094 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
19095 v8::DebugEvent event = event_details.GetEvent();
19096 if (event != v8::Break) return;
19097 Handle<Object> exec_state = event_details.GetExecutionState();
19098 Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
19099 CompileRun("function f(id) { new FrameDetails(id, 0); }");
19100 Handle<Function> fun =
19101 Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
19102 fun->Call(CcTest::global(), 1, &break_id);
19106 TEST(Regress385349) {
19107 i::FLAG_allow_natives_syntax = true;
19108 v8::Isolate* isolate = CcTest::isolate();
19109 HandleScope handle_scope(isolate);
19110 isolate->SetAutorunMicrotasks(false);
19111 Handle<Context> context = Context::New(isolate);
19112 v8::Debug::SetDebugEventListener(DebugEventInObserver);
19114 Context::Scope context_scope(context);
19115 CompileRun("var obj = {};"
19116 "Object.observe(obj, function(changes) { debugger; });"
19119 isolate->RunMicrotasks();
19120 isolate->SetAutorunMicrotasks(true);
19121 v8::Debug::SetDebugEventListener(NULL);
19125 #ifdef ENABLE_DISASSEMBLER
19126 static int probes_counter = 0;
19127 static int misses_counter = 0;
19128 static int updates_counter = 0;
19131 static int* LookupCounter(const char* name) {
19132 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
19133 return &probes_counter;
19134 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
19135 return &misses_counter;
19136 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
19137 return &updates_counter;
19143 static const char* kMegamorphicTestProgram =
19144 "function ClassA() { };"
19145 "function ClassB() { };"
19146 "ClassA.prototype.foo = function() { };"
19147 "ClassB.prototype.foo = function() { };"
19148 "function fooify(obj) { obj.foo(); };"
19149 "var a = new ClassA();"
19150 "var b = new ClassB();"
19151 "for (var i = 0; i < 10000; i++) {"
19158 static void StubCacheHelper(bool primary) {
19159 #ifdef ENABLE_DISASSEMBLER
19160 i::FLAG_native_code_counters = true;
19162 i::FLAG_test_primary_stub_cache = true;
19164 i::FLAG_test_secondary_stub_cache = true;
19166 i::FLAG_crankshaft = false;
19168 env->GetIsolate()->SetCounterFunction(LookupCounter);
19169 v8::HandleScope scope(env->GetIsolate());
19170 int initial_probes = probes_counter;
19171 int initial_misses = misses_counter;
19172 int initial_updates = updates_counter;
19173 CompileRun(kMegamorphicTestProgram);
19174 int probes = probes_counter - initial_probes;
19175 int misses = misses_counter - initial_misses;
19176 int updates = updates_counter - initial_updates;
19177 CHECK_LT(updates, 10);
19178 CHECK_LT(misses, 10);
19179 // TODO(verwaest): Update this test to overflow the degree of polymorphism
19180 // before megamorphism. The number of probes will only work once we teach the
19181 // serializer to embed references to counters in the stubs, given that the
19182 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
19183 CHECK_GE(probes, 0);
19188 TEST(SecondaryStubCache) {
19189 StubCacheHelper(true);
19193 TEST(PrimaryStubCache) {
19194 StubCacheHelper(false);
19199 static int cow_arrays_created_runtime = 0;
19202 static int* LookupCounterCOWArrays(const char* name) {
19203 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
19204 return &cow_arrays_created_runtime;
19211 TEST(CheckCOWArraysCreatedRuntimeCounter) {
19213 i::FLAG_native_code_counters = true;
19215 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
19216 v8::HandleScope scope(env->GetIsolate());
19217 int initial_cow_arrays = cow_arrays_created_runtime;
19218 CompileRun("var o = [1, 2, 3];");
19219 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
19220 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
19221 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
19222 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
19223 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
19228 TEST(StaticGetters) {
19229 LocalContext context;
19230 i::Factory* factory = CcTest::i_isolate()->factory();
19231 v8::Isolate* isolate = CcTest::isolate();
19232 v8::HandleScope scope(isolate);
19233 i::Handle<i::Object> undefined_value = factory->undefined_value();
19234 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
19235 i::Handle<i::Object> null_value = factory->null_value();
19236 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
19237 i::Handle<i::Object> true_value = factory->true_value();
19238 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
19239 i::Handle<i::Object> false_value = factory->false_value();
19240 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
19244 UNINITIALIZED_TEST(IsolateEmbedderData) {
19245 CcTest::DisableAutomaticDispose();
19246 v8::Isolate* isolate = v8::Isolate::New();
19248 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
19249 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19250 CHECK(!isolate->GetData(slot));
19251 CHECK(!i_isolate->GetData(slot));
19253 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19254 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
19255 isolate->SetData(slot, data);
19257 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19258 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
19259 CHECK_EQ(data, isolate->GetData(slot));
19260 CHECK_EQ(data, i_isolate->GetData(slot));
19262 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19263 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
19264 isolate->SetData(slot, data);
19266 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
19267 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
19268 CHECK_EQ(data, isolate->GetData(slot));
19269 CHECK_EQ(data, i_isolate->GetData(slot));
19272 isolate->Dispose();
19276 TEST(StringEmpty) {
19277 LocalContext context;
19278 i::Factory* factory = CcTest::i_isolate()->factory();
19279 v8::Isolate* isolate = CcTest::isolate();
19280 v8::HandleScope scope(isolate);
19281 i::Handle<i::Object> empty_string = factory->empty_string();
19282 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
19286 static int instance_checked_getter_count = 0;
19287 static void InstanceCheckedGetter(
19288 Local<String> name,
19289 const v8::PropertyCallbackInfo<v8::Value>& info) {
19290 CHECK(name->Equals(v8_str("foo")));
19291 instance_checked_getter_count++;
19292 info.GetReturnValue().Set(v8_num(11));
19296 static int instance_checked_setter_count = 0;
19297 static void InstanceCheckedSetter(Local<String> name,
19298 Local<Value> value,
19299 const v8::PropertyCallbackInfo<void>& info) {
19300 CHECK(name->Equals(v8_str("foo")));
19301 CHECK(value->Equals(v8_num(23)));
19302 instance_checked_setter_count++;
19306 static void CheckInstanceCheckedResult(int getters, int setters,
19307 bool expects_callbacks,
19308 TryCatch* try_catch) {
19309 if (expects_callbacks) {
19310 CHECK(!try_catch->HasCaught());
19311 CHECK_EQ(getters, instance_checked_getter_count);
19312 CHECK_EQ(setters, instance_checked_setter_count);
19314 CHECK(try_catch->HasCaught());
19315 CHECK_EQ(0, instance_checked_getter_count);
19316 CHECK_EQ(0, instance_checked_setter_count);
19318 try_catch->Reset();
19322 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
19323 instance_checked_getter_count = 0;
19324 instance_checked_setter_count = 0;
19325 TryCatch try_catch;
19327 // Test path through generic runtime code.
19328 CompileRun("obj.foo");
19329 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
19330 CompileRun("obj.foo = 23");
19331 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
19333 // Test path through generated LoadIC and StoredIC.
19334 CompileRun("function test_get(o) { o.foo; }"
19336 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
19337 CompileRun("test_get(obj);");
19338 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
19339 CompileRun("test_get(obj);");
19340 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
19341 CompileRun("function test_set(o) { o.foo = 23; }"
19343 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
19344 CompileRun("test_set(obj);");
19345 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
19346 CompileRun("test_set(obj);");
19347 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
19349 // Test path through optimized code.
19350 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
19352 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
19353 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
19355 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
19357 // Cleanup so that closures start out fresh in next check.
19358 CompileRun("%DeoptimizeFunction(test_get);"
19359 "%ClearFunctionTypeFeedback(test_get);"
19360 "%DeoptimizeFunction(test_set);"
19361 "%ClearFunctionTypeFeedback(test_set);");
19365 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
19366 v8::internal::FLAG_allow_natives_syntax = true;
19367 LocalContext context;
19368 v8::HandleScope scope(context->GetIsolate());
19370 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
19371 Local<ObjectTemplate> inst = templ->InstanceTemplate();
19372 inst->SetAccessor(v8_str("foo"),
19373 InstanceCheckedGetter, InstanceCheckedSetter,
19377 v8::AccessorSignature::New(context->GetIsolate(), templ));
19378 context->Global()->Set(v8_str("f"), templ->GetFunction());
19380 printf("Testing positive ...\n");
19381 CompileRun("var obj = new f();");
19382 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19383 CheckInstanceCheckedAccessors(true);
19385 printf("Testing negative ...\n");
19386 CompileRun("var obj = {};"
19387 "obj.__proto__ = new f();");
19388 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19389 CheckInstanceCheckedAccessors(false);
19393 static void EmptyInterceptorGetter(
19394 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
19397 static void EmptyInterceptorSetter(
19398 Local<String> name, Local<Value> value,
19399 const v8::PropertyCallbackInfo<v8::Value>& info) {}
19402 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
19403 v8::internal::FLAG_allow_natives_syntax = true;
19404 LocalContext context;
19405 v8::HandleScope scope(context->GetIsolate());
19407 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
19408 Local<ObjectTemplate> inst = templ->InstanceTemplate();
19409 templ->InstanceTemplate()->SetNamedPropertyHandler(EmptyInterceptorGetter,
19410 EmptyInterceptorSetter);
19411 inst->SetAccessor(v8_str("foo"),
19412 InstanceCheckedGetter, InstanceCheckedSetter,
19416 v8::AccessorSignature::New(context->GetIsolate(), templ));
19417 context->Global()->Set(v8_str("f"), templ->GetFunction());
19419 printf("Testing positive ...\n");
19420 CompileRun("var obj = new f();");
19421 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19422 CheckInstanceCheckedAccessors(true);
19424 printf("Testing negative ...\n");
19425 CompileRun("var obj = {};"
19426 "obj.__proto__ = new f();");
19427 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19428 CheckInstanceCheckedAccessors(false);
19432 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
19433 v8::internal::FLAG_allow_natives_syntax = true;
19434 LocalContext context;
19435 v8::HandleScope scope(context->GetIsolate());
19437 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
19438 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
19439 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
19440 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
19442 v8::AccessorSignature::New(context->GetIsolate(), templ));
19443 context->Global()->Set(v8_str("f"), templ->GetFunction());
19445 printf("Testing positive ...\n");
19446 CompileRun("var obj = new f();");
19447 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19448 CheckInstanceCheckedAccessors(true);
19450 printf("Testing negative ...\n");
19451 CompileRun("var obj = {};"
19452 "obj.__proto__ = new f();");
19453 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19454 CheckInstanceCheckedAccessors(false);
19456 printf("Testing positive with modified prototype chain ...\n");
19457 CompileRun("var obj = new f();"
19459 "pro.__proto__ = obj.__proto__;"
19460 "obj.__proto__ = pro;");
19461 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
19462 CheckInstanceCheckedAccessors(true);
19466 TEST(TryFinallyMessage) {
19467 LocalContext context;
19468 v8::HandleScope scope(context->GetIsolate());
19470 // Test that the original error message is not lost if there is a
19471 // recursive call into Javascript is done in the finally block, e.g. to
19472 // initialize an IC. (crbug.com/129171)
19473 TryCatch try_catch;
19474 const char* trigger_ic =
19476 " throw new Error('test'); \n"
19479 " x++; \n" // Trigger an IC initialization here.
19481 CompileRun(trigger_ic);
19482 CHECK(try_catch.HasCaught());
19483 Local<Message> message = try_catch.Message();
19484 CHECK(!message.IsEmpty());
19485 CHECK_EQ(2, message->GetLineNumber());
19489 // Test that the original exception message is indeed overwritten if
19490 // a new error is thrown in the finally block.
19491 TryCatch try_catch;
19492 const char* throw_again =
19494 " throw new Error('test'); \n"
19498 " throw new Error('again'); \n" // This is the new uncaught error.
19500 CompileRun(throw_again);
19501 CHECK(try_catch.HasCaught());
19502 Local<Message> message = try_catch.Message();
19503 CHECK(!message.IsEmpty());
19504 CHECK_EQ(6, message->GetLineNumber());
19509 static void Helper137002(bool do_store,
19511 bool remove_accessor,
19512 bool interceptor) {
19513 LocalContext context;
19514 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
19516 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
19517 FooSetInterceptor));
19519 templ->SetAccessor(v8_str("foo"),
19520 GetterWhichReturns42,
19521 SetterWhichSetsYOnThisTo23);
19523 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19525 // Turn monomorphic on slow object with native accessor, then turn
19526 // polymorphic, finally optimize to create negative lookup and fail.
19527 CompileRun(do_store ?
19528 "function f(x) { x.foo = void 0; }" :
19529 "function f(x) { return x.foo; }");
19530 CompileRun("obj.y = void 0;");
19531 if (!interceptor) {
19532 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
19534 CompileRun("obj.__proto__ = null;"
19535 "f(obj); f(obj); f(obj);");
19537 CompileRun("f({});");
19539 CompileRun("obj.y = void 0;"
19540 "%OptimizeFunctionOnNextCall(f);");
19541 if (remove_accessor) {
19542 CompileRun("delete obj.foo;");
19544 CompileRun("var result = f(obj);");
19546 CompileRun("result = obj.y;");
19548 if (remove_accessor && !interceptor) {
19549 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
19551 CHECK_EQ(do_store ? 23 : 42,
19552 context->Global()->Get(v8_str("result"))->Int32Value());
19557 THREADED_TEST(Regress137002a) {
19558 i::FLAG_allow_natives_syntax = true;
19559 i::FLAG_compilation_cache = false;
19560 v8::HandleScope scope(CcTest::isolate());
19561 for (int i = 0; i < 16; i++) {
19562 Helper137002(i & 8, i & 4, i & 2, i & 1);
19567 THREADED_TEST(Regress137002b) {
19568 i::FLAG_allow_natives_syntax = true;
19569 LocalContext context;
19570 v8::Isolate* isolate = context->GetIsolate();
19571 v8::HandleScope scope(isolate);
19572 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19573 templ->SetAccessor(v8_str("foo"),
19574 GetterWhichReturns42,
19575 SetterWhichSetsYOnThisTo23);
19576 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19578 // Turn monomorphic on slow object with native accessor, then just
19579 // delete the property and fail.
19580 CompileRun("function load(x) { return x.foo; }"
19581 "function store(x) { x.foo = void 0; }"
19582 "function keyed_load(x, key) { return x[key]; }"
19583 // Second version of function has a different source (add void 0)
19584 // so that it does not share code with the first version. This
19585 // ensures that the ICs are monomorphic.
19586 "function load2(x) { void 0; return x.foo; }"
19587 "function store2(x) { void 0; x.foo = void 0; }"
19588 "function keyed_load2(x, key) { void 0; return x[key]; }"
19591 "obj.__proto__ = null;"
19593 "subobj.y = void 0;"
19594 "subobj.__proto__ = obj;"
19595 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19597 // Make the ICs monomorphic.
19598 "load(obj); load(obj);"
19599 "load2(subobj); load2(subobj);"
19600 "store(obj); store(obj);"
19601 "store2(subobj); store2(subobj);"
19602 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
19603 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
19605 // Actually test the shiny new ICs and better not crash. This
19606 // serves as a regression test for issue 142088 as well.
19611 "keyed_load(obj, 'foo');"
19612 "keyed_load2(subobj, 'foo');"
19614 // Delete the accessor. It better not be called any more now.
19617 "subobj.y = void 0;"
19619 "var load_result = load(obj);"
19620 "var load_result2 = load2(subobj);"
19621 "var keyed_load_result = keyed_load(obj, 'foo');"
19622 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
19625 "var y_from_obj = obj.y;"
19626 "var y_from_subobj = subobj.y;");
19627 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
19628 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
19629 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
19630 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
19631 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
19632 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
19636 THREADED_TEST(Regress142088) {
19637 i::FLAG_allow_natives_syntax = true;
19638 LocalContext context;
19639 v8::Isolate* isolate = context->GetIsolate();
19640 v8::HandleScope scope(isolate);
19641 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19642 templ->SetAccessor(v8_str("foo"),
19643 GetterWhichReturns42,
19644 SetterWhichSetsYOnThisTo23);
19645 context->Global()->Set(v8_str("obj"), templ->NewInstance());
19647 CompileRun("function load(x) { return x.foo; }"
19648 "var o = Object.create(obj);"
19649 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
19650 "load(o); load(o); load(o); load(o);");
19654 THREADED_TEST(Regress3337) {
19655 LocalContext context;
19656 v8::Isolate* isolate = context->GetIsolate();
19657 v8::HandleScope scope(isolate);
19658 Local<v8::Object> o1 = Object::New(isolate);
19659 Local<v8::Object> o2 = Object::New(isolate);
19660 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
19661 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
19662 CHECK(io1->map() == io2->map());
19663 o1->SetIndexedPropertiesToExternalArrayData(
19664 NULL, v8::kExternalUint32Array, 0);
19665 o2->SetIndexedPropertiesToExternalArrayData(
19666 NULL, v8::kExternalUint32Array, 0);
19667 CHECK(io1->map() == io2->map());
19671 THREADED_TEST(Regress137496) {
19672 i::FLAG_expose_gc = true;
19673 LocalContext context;
19674 v8::HandleScope scope(context->GetIsolate());
19676 // Compile a try-finally clause where the finally block causes a GC
19677 // while there still is a message pending for external reporting.
19678 TryCatch try_catch;
19679 try_catch.SetVerbose(true);
19680 CompileRun("try { throw new Error(); } finally { gc(); }");
19681 CHECK(try_catch.HasCaught());
19685 THREADED_TEST(Regress157124) {
19686 LocalContext context;
19687 v8::Isolate* isolate = context->GetIsolate();
19688 v8::HandleScope scope(isolate);
19689 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19690 Local<Object> obj = templ->NewInstance();
19691 obj->GetIdentityHash();
19692 obj->DeleteHiddenValue(v8_str("Bug"));
19696 THREADED_TEST(Regress2535) {
19697 LocalContext context;
19698 v8::HandleScope scope(context->GetIsolate());
19699 Local<Value> set_value = CompileRun("new Set();");
19700 Local<Object> set_object(Local<Object>::Cast(set_value));
19701 CHECK_EQ(0, set_object->InternalFieldCount());
19702 Local<Value> map_value = CompileRun("new Map();");
19703 Local<Object> map_object(Local<Object>::Cast(map_value));
19704 CHECK_EQ(0, map_object->InternalFieldCount());
19708 THREADED_TEST(Regress2746) {
19709 LocalContext context;
19710 v8::Isolate* isolate = context->GetIsolate();
19711 v8::HandleScope scope(isolate);
19712 Local<Object> obj = Object::New(isolate);
19713 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
19714 obj->SetHiddenValue(key, v8::Undefined(isolate));
19715 Local<Value> value = obj->GetHiddenValue(key);
19716 CHECK(!value.IsEmpty());
19717 CHECK(value->IsUndefined());
19721 THREADED_TEST(Regress260106) {
19722 LocalContext context;
19723 v8::Isolate* isolate = context->GetIsolate();
19724 v8::HandleScope scope(isolate);
19725 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
19727 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
19728 Local<Function> function = templ->GetFunction();
19729 CHECK(!function.IsEmpty());
19730 CHECK(function->IsFunction());
19734 THREADED_TEST(JSONParseObject) {
19735 LocalContext context;
19736 HandleScope scope(context->GetIsolate());
19737 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
19738 Handle<Object> global = context->Global();
19739 global->Set(v8_str("obj"), obj);
19740 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
19744 THREADED_TEST(JSONParseNumber) {
19745 LocalContext context;
19746 HandleScope scope(context->GetIsolate());
19747 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
19748 Handle<Object> global = context->Global();
19749 global->Set(v8_str("obj"), obj);
19750 ExpectString("JSON.stringify(obj)", "42");
19754 #if V8_OS_POSIX && !V8_OS_NACL
19755 class ThreadInterruptTest {
19757 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
19758 ~ThreadInterruptTest() {}
19761 InterruptThread i_thread(this);
19765 CHECK_EQ(kExpectedValue, sem_value_);
19769 static const int kExpectedValue = 1;
19771 class InterruptThread : public v8::base::Thread {
19773 explicit InterruptThread(ThreadInterruptTest* test)
19774 : Thread(Options("InterruptThread")), test_(test) {}
19776 virtual void Run() {
19777 struct sigaction action;
19779 // Ensure that we'll enter waiting condition
19780 v8::base::OS::Sleep(100);
19782 // Setup signal handler
19783 memset(&action, 0, sizeof(action));
19784 action.sa_handler = SignalHandler;
19785 sigaction(SIGCHLD, &action, NULL);
19788 kill(getpid(), SIGCHLD);
19790 // Ensure that if wait has returned because of error
19791 v8::base::OS::Sleep(100);
19793 // Set value and signal semaphore
19794 test_->sem_value_ = 1;
19795 test_->sem_.Signal();
19798 static void SignalHandler(int signal) {
19802 ThreadInterruptTest* test_;
19805 v8::base::Semaphore sem_;
19806 volatile int sem_value_;
19810 THREADED_TEST(SemaphoreInterruption) {
19811 ThreadInterruptTest().RunTest();
19815 #endif // V8_OS_POSIX
19818 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
19820 v8::AccessType type,
19821 Local<Value> data) {
19822 i::PrintF("Named access blocked.\n");
19827 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
19829 v8::AccessType type,
19830 Local<Value> data) {
19831 i::PrintF("Indexed access blocked.\n");
19836 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19841 TEST(JSONStringifyAccessCheck) {
19842 v8::V8::Initialize();
19843 v8::Isolate* isolate = CcTest::isolate();
19844 v8::HandleScope scope(isolate);
19846 // Create an ObjectTemplate for global objects and install access
19847 // check callbacks that will block access.
19848 v8::Handle<v8::ObjectTemplate> global_template =
19849 v8::ObjectTemplate::New(isolate);
19850 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
19851 IndexAccessAlwaysBlocked);
19853 // Create a context and set an x property on it's global object.
19854 LocalContext context0(NULL, global_template);
19855 v8::Handle<v8::Object> global0 = context0->Global();
19856 global0->Set(v8_str("x"), v8_num(42));
19857 ExpectString("JSON.stringify(this)", "{\"x\":42}");
19859 for (int i = 0; i < 2; i++) {
19861 // Install a toJSON function on the second run.
19862 v8::Handle<v8::FunctionTemplate> toJSON =
19863 v8::FunctionTemplate::New(isolate, UnreachableCallback);
19865 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
19867 // Create a context with a different security token so that the
19868 // failed access check callback will be called on each access.
19869 LocalContext context1(NULL, global_template);
19870 context1->Global()->Set(v8_str("other"), global0);
19872 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
19873 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
19874 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
19876 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
19877 array->Set(0, v8_str("a"));
19878 array->Set(1, v8_str("b"));
19879 context1->Global()->Set(v8_str("array"), array);
19880 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
19881 array->TurnOnAccessCheck();
19882 CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
19883 CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
19884 CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
19889 bool access_check_fail_thrown = false;
19890 bool catch_callback_called = false;
19893 // Failed access check callback that performs a GC on each invocation.
19894 void FailedAccessCheckThrows(Local<v8::Object> target,
19895 v8::AccessType type,
19896 Local<v8::Value> data) {
19897 access_check_fail_thrown = true;
19898 i::PrintF("Access check failed. Error thrown.\n");
19899 CcTest::isolate()->ThrowException(
19900 v8::Exception::Error(v8_str("cross context")));
19904 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19905 for (int i = 0; i < args.Length(); i++) {
19906 i::PrintF("%s\n", *String::Utf8Value(args[i]));
19908 catch_callback_called = true;
19912 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
19913 args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
19914 args[1]->ToString(args.GetIsolate()));
19918 void CheckCorrectThrow(const char* script) {
19919 // Test that the script, when wrapped into a try-catch, triggers the catch
19920 // clause due to failed access check throwing an exception.
19921 // The subsequent try-catch should run without any exception.
19922 access_check_fail_thrown = false;
19923 catch_callback_called = false;
19924 i::ScopedVector<char> source(1024);
19925 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
19926 CompileRun(source.start());
19927 CHECK(access_check_fail_thrown);
19928 CHECK(catch_callback_called);
19930 access_check_fail_thrown = false;
19931 catch_callback_called = false;
19932 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
19933 CHECK(!access_check_fail_thrown);
19934 CHECK(!catch_callback_called);
19938 TEST(AccessCheckThrows) {
19939 i::FLAG_allow_natives_syntax = true;
19940 v8::V8::Initialize();
19941 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
19942 v8::Isolate* isolate = CcTest::isolate();
19943 v8::HandleScope scope(isolate);
19945 // Create an ObjectTemplate for global objects and install access
19946 // check callbacks that will block access.
19947 v8::Handle<v8::ObjectTemplate> global_template =
19948 v8::ObjectTemplate::New(isolate);
19949 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
19950 IndexAccessAlwaysBlocked);
19952 // Create a context and set an x property on it's global object.
19953 LocalContext context0(NULL, global_template);
19954 v8::Handle<v8::Object> global0 = context0->Global();
19956 // Create a context with a different security token so that the
19957 // failed access check callback will be called on each access.
19958 LocalContext context1(NULL, global_template);
19959 context1->Global()->Set(v8_str("other"), global0);
19961 v8::Handle<v8::FunctionTemplate> catcher_fun =
19962 v8::FunctionTemplate::New(isolate, CatcherCallback);
19963 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
19965 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
19966 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
19967 context1->Global()->Set(v8_str("has_own_property"),
19968 has_own_property_fun->GetFunction());
19970 { v8::TryCatch try_catch;
19971 access_check_fail_thrown = false;
19972 CompileRun("other.x;");
19973 CHECK(access_check_fail_thrown);
19974 CHECK(try_catch.HasCaught());
19977 CheckCorrectThrow("other.x");
19978 CheckCorrectThrow("other[1]");
19979 CheckCorrectThrow("JSON.stringify(other)");
19980 CheckCorrectThrow("has_own_property(other, 'x')");
19981 CheckCorrectThrow("%GetProperty(other, 'x')");
19982 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
19983 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
19984 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
19985 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
19986 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
19987 CheckCorrectThrow("%HasProperty(other, 'x')");
19988 CheckCorrectThrow("%HasElement(other, 1)");
19989 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
19990 CheckCorrectThrow("%GetPropertyNames(other)");
19991 // PROPERTY_ATTRIBUTES_NONE = 0
19992 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
19993 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
19994 "other, 'x', null, null, 1)");
19996 // Reset the failed access check callback so it does not influence
19997 // the other tests.
19998 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
20002 class RequestInterruptTestBase {
20004 RequestInterruptTestBase()
20006 isolate_(env_->GetIsolate()),
20009 should_continue_(true) {
20012 virtual ~RequestInterruptTestBase() { }
20014 virtual void StartInterruptThread() = 0;
20016 virtual void TestBody() = 0;
20019 StartInterruptThread();
20021 v8::HandleScope handle_scope(isolate_);
20025 // Verify we arrived here because interruptor was called
20026 // not due to a bug causing us to exit the loop too early.
20027 CHECK(!should_continue());
20030 void WakeUpInterruptor() {
20034 bool should_continue() const { return should_continue_; }
20036 bool ShouldContinue() {
20038 if (--warmup_ == 0) {
20039 WakeUpInterruptor();
20043 return should_continue_;
20046 static void ShouldContinueCallback(
20047 const v8::FunctionCallbackInfo<Value>& info) {
20048 RequestInterruptTestBase* test =
20049 reinterpret_cast<RequestInterruptTestBase*>(
20050 info.Data().As<v8::External>()->Value());
20051 info.GetReturnValue().Set(test->ShouldContinue());
20055 v8::Isolate* isolate_;
20056 v8::base::Semaphore sem_;
20058 bool should_continue_;
20062 class RequestInterruptTestBaseWithSimpleInterrupt
20063 : public RequestInterruptTestBase {
20065 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
20067 virtual void StartInterruptThread() {
20072 class InterruptThread : public v8::base::Thread {
20074 explicit InterruptThread(RequestInterruptTestBase* test)
20075 : Thread(Options("RequestInterruptTest")), test_(test) {}
20077 virtual void Run() {
20078 test_->sem_.Wait();
20079 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
20082 static void OnInterrupt(v8::Isolate* isolate, void* data) {
20083 reinterpret_cast<RequestInterruptTestBase*>(data)->
20084 should_continue_ = false;
20088 RequestInterruptTestBase* test_;
20091 InterruptThread i_thread;
20095 class RequestInterruptTestWithFunctionCall
20096 : public RequestInterruptTestBaseWithSimpleInterrupt {
20098 virtual void TestBody() {
20099 Local<Function> func = Function::New(
20100 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
20101 env_->Global()->Set(v8_str("ShouldContinue"), func);
20103 CompileRun("while (ShouldContinue()) { }");
20108 class RequestInterruptTestWithMethodCall
20109 : public RequestInterruptTestBaseWithSimpleInterrupt {
20111 virtual void TestBody() {
20112 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20113 v8::Local<v8::Template> proto = t->PrototypeTemplate();
20114 proto->Set(v8_str("shouldContinue"), Function::New(
20115 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
20116 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20118 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
20123 class RequestInterruptTestWithAccessor
20124 : public RequestInterruptTestBaseWithSimpleInterrupt {
20126 virtual void TestBody() {
20127 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20128 v8::Local<v8::Template> proto = t->PrototypeTemplate();
20129 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
20130 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
20131 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20133 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
20138 class RequestInterruptTestWithNativeAccessor
20139 : public RequestInterruptTestBaseWithSimpleInterrupt {
20141 virtual void TestBody() {
20142 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20143 t->InstanceTemplate()->SetNativeDataProperty(
20144 v8_str("shouldContinue"),
20145 &ShouldContinueNativeGetter,
20147 v8::External::New(isolate_, this));
20148 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20150 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
20154 static void ShouldContinueNativeGetter(
20155 Local<String> property,
20156 const v8::PropertyCallbackInfo<v8::Value>& info) {
20157 RequestInterruptTestBase* test =
20158 reinterpret_cast<RequestInterruptTestBase*>(
20159 info.Data().As<v8::External>()->Value());
20160 info.GetReturnValue().Set(test->ShouldContinue());
20165 class RequestInterruptTestWithMethodCallAndInterceptor
20166 : public RequestInterruptTestBaseWithSimpleInterrupt {
20168 virtual void TestBody() {
20169 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
20170 v8::Local<v8::Template> proto = t->PrototypeTemplate();
20171 proto->Set(v8_str("shouldContinue"), Function::New(
20172 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
20173 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
20174 instance_template->SetHandler(
20175 v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
20177 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
20179 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
20183 static void EmptyInterceptor(
20184 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
20188 class RequestInterruptTestWithMathAbs
20189 : public RequestInterruptTestBaseWithSimpleInterrupt {
20191 virtual void TestBody() {
20192 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
20194 WakeUpInterruptorCallback,
20195 v8::External::New(isolate_, this)));
20197 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
20199 ShouldContinueCallback,
20200 v8::External::New(isolate_, this)));
20202 i::FLAG_allow_natives_syntax = true;
20203 CompileRun("function loopish(o) {"
20205 " while (o.abs(1) > 0) {"
20206 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
20208 " if (--pre === 0) WakeUpInterruptor(o === Math);"
20213 "var obj = {abs: function () { return i-- }, x: null};"
20216 "%OptimizeFunctionOnNextCall(loopish);"
20219 i::FLAG_allow_natives_syntax = false;
20223 static void WakeUpInterruptorCallback(
20224 const v8::FunctionCallbackInfo<Value>& info) {
20225 if (!info[0]->BooleanValue()) return;
20227 RequestInterruptTestBase* test =
20228 reinterpret_cast<RequestInterruptTestBase*>(
20229 info.Data().As<v8::External>()->Value());
20230 test->WakeUpInterruptor();
20233 static void ShouldContinueCallback(
20234 const v8::FunctionCallbackInfo<Value>& info) {
20235 RequestInterruptTestBase* test =
20236 reinterpret_cast<RequestInterruptTestBase*>(
20237 info.Data().As<v8::External>()->Value());
20238 info.GetReturnValue().Set(test->should_continue());
20243 TEST(RequestInterruptTestWithFunctionCall) {
20244 RequestInterruptTestWithFunctionCall().RunTest();
20248 TEST(RequestInterruptTestWithMethodCall) {
20249 RequestInterruptTestWithMethodCall().RunTest();
20253 TEST(RequestInterruptTestWithAccessor) {
20254 RequestInterruptTestWithAccessor().RunTest();
20258 TEST(RequestInterruptTestWithNativeAccessor) {
20259 RequestInterruptTestWithNativeAccessor().RunTest();
20263 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
20264 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
20268 TEST(RequestInterruptTestWithMathAbs) {
20269 RequestInterruptTestWithMathAbs().RunTest();
20273 class RequestMultipleInterrupts : public RequestInterruptTestBase {
20275 RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
20277 virtual void StartInterruptThread() {
20281 virtual void TestBody() {
20282 Local<Function> func = Function::New(
20283 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
20284 env_->Global()->Set(v8_str("ShouldContinue"), func);
20286 CompileRun("while (ShouldContinue()) { }");
20290 class InterruptThread : public v8::base::Thread {
20292 enum { NUM_INTERRUPTS = 10 };
20293 explicit InterruptThread(RequestMultipleInterrupts* test)
20294 : Thread(Options("RequestInterruptTest")), test_(test) {}
20296 virtual void Run() {
20297 test_->sem_.Wait();
20298 for (int i = 0; i < NUM_INTERRUPTS; i++) {
20299 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
20303 static void OnInterrupt(v8::Isolate* isolate, void* data) {
20304 RequestMultipleInterrupts* test =
20305 reinterpret_cast<RequestMultipleInterrupts*>(data);
20306 test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
20310 RequestMultipleInterrupts* test_;
20313 InterruptThread i_thread;
20318 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
20321 static Local<Value> function_new_expected_env;
20322 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
20323 CHECK(function_new_expected_env->Equals(info.Data()));
20324 info.GetReturnValue().Set(17);
20328 THREADED_TEST(FunctionNew) {
20330 v8::Isolate* isolate = env->GetIsolate();
20331 v8::HandleScope scope(isolate);
20332 Local<Object> data = v8::Object::New(isolate);
20333 function_new_expected_env = data;
20334 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
20335 env->Global()->Set(v8_str("func"), func);
20336 Local<Value> result = CompileRun("func();");
20337 CHECK(v8::Integer::New(isolate, 17)->Equals(result));
20338 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
20339 // Verify function not cached
20340 auto serial_number = handle(i::Smi::cast(v8::Utils::OpenHandle(*func)
20342 ->get_api_func_data()
20343 ->serial_number()),
20345 auto cache = i_isolate->function_cache();
20346 CHECK(cache->Lookup(serial_number)->IsTheHole());
20347 // Verify that each Function::New creates a new function instance
20348 Local<Object> data2 = v8::Object::New(isolate);
20349 function_new_expected_env = data2;
20350 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
20351 CHECK(!func2->IsNull());
20352 CHECK(!func->Equals(func2));
20353 env->Global()->Set(v8_str("func2"), func2);
20354 Local<Value> result2 = CompileRun("func2();");
20355 CHECK(v8::Integer::New(isolate, 17)->Equals(result2));
20359 TEST(EscapeableHandleScope) {
20360 HandleScope outer_scope(CcTest::isolate());
20361 LocalContext context;
20362 const int runs = 10;
20363 Local<String> values[runs];
20364 for (int i = 0; i < runs; i++) {
20365 v8::EscapableHandleScope inner_scope(CcTest::isolate());
20366 Local<String> value;
20367 if (i != 0) value = v8_str("escape value");
20368 values[i] = inner_scope.Escape(value);
20370 for (int i = 0; i < runs; i++) {
20371 Local<String> expected;
20373 CHECK(v8_str("escape value")->Equals(values[i]));
20375 CHECK(values[i].IsEmpty());
20381 static void SetterWhichExpectsThisAndHolderToDiffer(
20382 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
20383 CHECK(info.Holder() != info.This());
20387 TEST(Regress239669) {
20388 LocalContext context;
20389 v8::Isolate* isolate = context->GetIsolate();
20390 v8::HandleScope scope(isolate);
20391 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20392 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
20393 context->Global()->Set(v8_str("P"), templ->NewInstance());
20398 "C1.prototype = P;"
20399 "for (var i = 0; i < 4; i++ ) {"
20405 class ApiCallOptimizationChecker {
20407 static Local<Object> data;
20408 static Local<Object> receiver;
20409 static Local<Object> holder;
20410 static Local<Object> callee;
20413 static void OptimizationCallback(
20414 const v8::FunctionCallbackInfo<v8::Value>& info) {
20415 CHECK(callee == info.Callee());
20416 CHECK(data == info.Data());
20417 CHECK(receiver == info.This());
20418 if (info.Length() == 1) {
20419 CHECK(v8_num(1)->Equals(info[0]));
20421 CHECK(holder == info.Holder());
20423 info.GetReturnValue().Set(v8_str("returned"));
20427 enum SignatureType {
20429 kSignatureOnReceiver,
20430 kSignatureOnPrototype
20434 SignatureType signature_types[] =
20435 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
20436 for (unsigned i = 0; i < arraysize(signature_types); i++) {
20437 SignatureType signature_type = signature_types[i];
20438 for (int j = 0; j < 2; j++) {
20439 bool global = j == 0;
20440 int key = signature_type +
20441 arraysize(signature_types) * (global ? 1 : 0);
20442 Run(signature_type, global, key);
20447 void Run(SignatureType signature_type, bool global, int key) {
20448 v8::Isolate* isolate = CcTest::isolate();
20449 v8::HandleScope scope(isolate);
20450 // Build a template for signature checks.
20451 Local<v8::ObjectTemplate> signature_template;
20452 Local<v8::Signature> signature;
20454 Local<v8::FunctionTemplate> parent_template =
20455 FunctionTemplate::New(isolate);
20456 parent_template->SetHiddenPrototype(true);
20457 Local<v8::FunctionTemplate> function_template
20458 = FunctionTemplate::New(isolate);
20459 function_template->Inherit(parent_template);
20460 switch (signature_type) {
20463 case kSignatureOnReceiver:
20464 signature = v8::Signature::New(isolate, function_template);
20466 case kSignatureOnPrototype:
20467 signature = v8::Signature::New(isolate, parent_template);
20470 signature_template = function_template->InstanceTemplate();
20472 // Global object must pass checks.
20473 Local<v8::Context> context =
20474 v8::Context::New(isolate, NULL, signature_template);
20475 v8::Context::Scope context_scope(context);
20476 // Install regular object that can pass signature checks.
20477 Local<Object> function_receiver = signature_template->NewInstance();
20478 context->Global()->Set(v8_str("function_receiver"), function_receiver);
20479 // Get the holder objects.
20480 Local<Object> inner_global =
20481 Local<Object>::Cast(context->Global()->GetPrototype());
20482 // Install functions on hidden prototype object if there is one.
20483 data = Object::New(isolate);
20484 Local<FunctionTemplate> function_template = FunctionTemplate::New(
20485 isolate, OptimizationCallback, data, signature);
20486 Local<Function> function = function_template->GetFunction();
20487 Local<Object> global_holder = inner_global;
20488 Local<Object> function_holder = function_receiver;
20489 if (signature_type == kSignatureOnPrototype) {
20490 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
20491 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
20493 global_holder->Set(v8_str("g_f"), function);
20494 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
20495 function_holder->Set(v8_str("f"), function);
20496 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
20497 // Initialize expected values.
20501 receiver = context->Global();
20502 holder = inner_global;
20504 holder = function_receiver;
20505 // If not using a signature, add something else to the prototype chain
20506 // to test the case that holder != receiver
20507 if (signature_type == kNoSignature) {
20508 receiver = Local<Object>::Cast(CompileRun(
20509 "var receiver_subclass = {};\n"
20510 "receiver_subclass.__proto__ = function_receiver;\n"
20511 "receiver_subclass"));
20513 receiver = Local<Object>::Cast(CompileRun(
20514 "var receiver_subclass = function_receiver;\n"
20515 "receiver_subclass"));
20518 // With no signature, the holder is not set.
20519 if (signature_type == kNoSignature) holder = receiver;
20520 // build wrap_function
20521 i::ScopedVector<char> wrap_function(200);
20525 "function wrap_f_%d() { var f = g_f; return f(); }\n"
20526 "function wrap_get_%d() { return this.g_acc; }\n"
20527 "function wrap_set_%d() { return this.g_acc = 1; }\n",
20532 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
20533 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
20534 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
20537 // build source string
20538 i::ScopedVector<char> source(1000);
20541 "%s\n" // wrap functions
20542 "function wrap_f() { return wrap_f_%d(); }\n"
20543 "function wrap_get() { return wrap_get_%d(); }\n"
20544 "function wrap_set() { return wrap_set_%d(); }\n"
20545 "check = function(returned) {\n"
20546 " if (returned !== 'returned') { throw returned; }\n"
20549 "check(wrap_f());\n"
20550 "check(wrap_f());\n"
20551 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
20552 "check(wrap_f());\n"
20554 "check(wrap_get());\n"
20555 "check(wrap_get());\n"
20556 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
20557 "check(wrap_get());\n"
20559 "check = function(returned) {\n"
20560 " if (returned !== 1) { throw returned; }\n"
20562 "check(wrap_set());\n"
20563 "check(wrap_set());\n"
20564 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
20565 "check(wrap_set());\n",
20566 wrap_function.start(), key, key, key, key, key, key);
20567 v8::TryCatch try_catch;
20568 CompileRun(source.start());
20569 DCHECK(!try_catch.HasCaught());
20570 CHECK_EQ(9, count);
20575 Local<Object> ApiCallOptimizationChecker::data;
20576 Local<Object> ApiCallOptimizationChecker::receiver;
20577 Local<Object> ApiCallOptimizationChecker::holder;
20578 Local<Object> ApiCallOptimizationChecker::callee;
20579 int ApiCallOptimizationChecker::count = 0;
20582 TEST(FunctionCallOptimization) {
20583 i::FLAG_allow_natives_syntax = true;
20584 ApiCallOptimizationChecker checker;
20589 TEST(FunctionCallOptimizationMultipleArgs) {
20590 i::FLAG_allow_natives_syntax = true;
20591 LocalContext context;
20592 v8::Isolate* isolate = context->GetIsolate();
20593 v8::HandleScope scope(isolate);
20594 Handle<Object> global = context->Global();
20595 Local<v8::Function> function = Function::New(isolate, Returns42);
20596 global->Set(v8_str("x"), function);
20598 "function x_wrap() {\n"
20599 " for (var i = 0; i < 5; i++) {\n"
20604 "%OptimizeFunctionOnNextCall(x_wrap);"
20609 static void ReturnsSymbolCallback(
20610 const v8::FunctionCallbackInfo<v8::Value>& info) {
20611 info.GetReturnValue().Set(v8::Symbol::New(info.GetIsolate()));
20615 TEST(ApiCallbackCanReturnSymbols) {
20616 i::FLAG_allow_natives_syntax = true;
20617 LocalContext context;
20618 v8::Isolate* isolate = context->GetIsolate();
20619 v8::HandleScope scope(isolate);
20620 Handle<Object> global = context->Global();
20621 Local<v8::Function> function = Function::New(isolate, ReturnsSymbolCallback);
20622 global->Set(v8_str("x"), function);
20624 "function x_wrap() {\n"
20625 " for (var i = 0; i < 5; i++) {\n"
20630 "%OptimizeFunctionOnNextCall(x_wrap);"
20635 TEST(EmptyApiCallback) {
20636 LocalContext context;
20637 auto isolate = context->GetIsolate();
20638 v8::HandleScope scope(isolate);
20639 auto global = context->Global();
20640 auto function = FunctionTemplate::New(isolate)->GetFunction();
20641 global->Set(v8_str("x"), function);
20643 auto result = CompileRun("x()");
20644 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20646 result = CompileRun("x(1,2,3)");
20647 CHECK(v8::Utils::OpenHandle(*result)->IsJSGlobalProxy());
20649 result = CompileRun("7 + x.call(3) + 11");
20650 CHECK(result->IsInt32());
20651 CHECK_EQ(21, result->Int32Value());
20653 result = CompileRun("7 + x.call(3, 101, 102, 103, 104) + 11");
20654 CHECK(result->IsInt32());
20655 CHECK_EQ(21, result->Int32Value());
20657 result = CompileRun("var y = []; x.call(y)");
20658 CHECK(result->IsArray());
20660 result = CompileRun("x.call(y, 1, 2, 3, 4)");
20661 CHECK(result->IsArray());
20665 TEST(SimpleSignatureCheck) {
20666 LocalContext context;
20667 auto isolate = context->GetIsolate();
20668 v8::HandleScope scope(isolate);
20669 auto global = context->Global();
20670 auto sig_obj = FunctionTemplate::New(isolate);
20671 auto sig = v8::Signature::New(isolate, sig_obj);
20672 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20673 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20674 global->Set(v8_str("x"), x->GetFunction());
20675 CompileRun("var s = new sig_obj();");
20677 TryCatch try_catch(isolate);
20679 CHECK(try_catch.HasCaught());
20682 TryCatch try_catch(isolate);
20683 CompileRun("x.call(1)");
20684 CHECK(try_catch.HasCaught());
20687 TryCatch try_catch(isolate);
20688 auto result = CompileRun("s.x = x; s.x()");
20689 CHECK(!try_catch.HasCaught());
20690 CHECK_EQ(42, result->Int32Value());
20693 TryCatch try_catch(isolate);
20694 auto result = CompileRun("x.call(s)");
20695 CHECK(!try_catch.HasCaught());
20696 CHECK_EQ(42, result->Int32Value());
20701 TEST(ChainSignatureCheck) {
20702 LocalContext context;
20703 auto isolate = context->GetIsolate();
20704 v8::HandleScope scope(isolate);
20705 auto global = context->Global();
20706 auto sig_obj = FunctionTemplate::New(isolate);
20707 auto sig = v8::Signature::New(isolate, sig_obj);
20708 for (int i = 0; i < 4; ++i) {
20709 auto temp = FunctionTemplate::New(isolate);
20710 temp->Inherit(sig_obj);
20713 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20714 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20715 global->Set(v8_str("x"), x->GetFunction());
20716 CompileRun("var s = new sig_obj();");
20718 TryCatch try_catch(isolate);
20720 CHECK(try_catch.HasCaught());
20723 TryCatch try_catch(isolate);
20724 CompileRun("x.call(1)");
20725 CHECK(try_catch.HasCaught());
20728 TryCatch try_catch(isolate);
20729 auto result = CompileRun("s.x = x; s.x()");
20730 CHECK(!try_catch.HasCaught());
20731 CHECK_EQ(42, result->Int32Value());
20734 TryCatch try_catch(isolate);
20735 auto result = CompileRun("x.call(s)");
20736 CHECK(!try_catch.HasCaught());
20737 CHECK_EQ(42, result->Int32Value());
20742 TEST(PrototypeSignatureCheck) {
20743 LocalContext context;
20744 auto isolate = context->GetIsolate();
20745 v8::HandleScope scope(isolate);
20746 auto global = context->Global();
20747 auto sig_obj = FunctionTemplate::New(isolate);
20748 sig_obj->SetHiddenPrototype(true);
20749 auto sig = v8::Signature::New(isolate, sig_obj);
20750 auto x = FunctionTemplate::New(isolate, Returns42, Handle<Value>(), sig);
20751 global->Set(v8_str("sig_obj"), sig_obj->GetFunction());
20752 global->Set(v8_str("x"), x->GetFunction());
20753 CompileRun("s = {}; s.__proto__ = new sig_obj();");
20755 TryCatch try_catch(isolate);
20757 CHECK(try_catch.HasCaught());
20760 TryCatch try_catch(isolate);
20761 CompileRun("x.call(1)");
20762 CHECK(try_catch.HasCaught());
20765 TryCatch try_catch(isolate);
20766 auto result = CompileRun("s.x = x; s.x()");
20767 CHECK(!try_catch.HasCaught());
20768 CHECK_EQ(42, result->Int32Value());
20771 TryCatch try_catch(isolate);
20772 auto result = CompileRun("x.call(s)");
20773 CHECK(!try_catch.HasCaught());
20774 CHECK_EQ(42, result->Int32Value());
20779 static const char* last_event_message;
20780 static int last_event_status;
20781 void StoringEventLoggerCallback(const char* message, int status) {
20782 last_event_message = message;
20783 last_event_status = status;
20787 TEST(EventLogging) {
20788 v8::Isolate* isolate = CcTest::isolate();
20789 isolate->SetEventLogger(StoringEventLoggerCallback);
20790 v8::internal::HistogramTimer histogramTimer(
20791 "V8.Test", 0, 10000, v8::internal::HistogramTimer::MILLISECOND, 50,
20792 reinterpret_cast<v8::internal::Isolate*>(isolate));
20793 histogramTimer.Start();
20794 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20795 CHECK_EQ(0, last_event_status);
20796 histogramTimer.Stop();
20797 CHECK_EQ(0, strcmp("V8.Test", last_event_message));
20798 CHECK_EQ(1, last_event_status);
20803 LocalContext context;
20804 v8::Isolate* isolate = context->GetIsolate();
20805 v8::HandleScope scope(isolate);
20806 Handle<Object> global = context->Global();
20809 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20810 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
20811 Handle<v8::Promise> p = pr->GetPromise();
20812 Handle<v8::Promise> r = rr->GetPromise();
20813 CHECK_EQ(isolate, p->GetIsolate());
20815 // IsPromise predicate.
20816 CHECK(p->IsPromise());
20817 CHECK(r->IsPromise());
20818 Handle<Value> o = v8::Object::New(isolate);
20819 CHECK(!o->IsPromise());
20821 // Resolution and rejection.
20822 pr->Resolve(v8::Integer::New(isolate, 1));
20823 CHECK(p->IsPromise());
20824 rr->Reject(v8::Integer::New(isolate, 2));
20825 CHECK(r->IsPromise());
20827 // Chaining non-pending promises.
20831 "function f1(x) { x1 = x; return x+1 };\n"
20832 "function f2(x) { x2 = x; return x+1 };\n");
20833 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20834 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20837 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20838 isolate->RunMicrotasks();
20839 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20842 isolate->RunMicrotasks();
20843 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20846 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20847 isolate->RunMicrotasks();
20848 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20851 isolate->RunMicrotasks();
20852 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20854 // Chaining pending promises.
20855 CompileRun("x1 = x2 = 0;");
20856 pr = v8::Promise::Resolver::New(isolate);
20857 rr = v8::Promise::Resolver::New(isolate);
20859 pr->GetPromise()->Chain(f1);
20860 rr->GetPromise()->Catch(f2);
20861 isolate->RunMicrotasks();
20862 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20863 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20865 pr->Resolve(v8::Integer::New(isolate, 1));
20866 rr->Reject(v8::Integer::New(isolate, 2));
20867 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20868 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20870 isolate->RunMicrotasks();
20871 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20872 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
20875 CompileRun("x1 = x2 = 0;");
20876 pr = v8::Promise::Resolver::New(isolate);
20877 pr->GetPromise()->Chain(f1)->Chain(f2);
20878 pr->Resolve(v8::Integer::New(isolate, 3));
20879 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20880 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20881 isolate->RunMicrotasks();
20882 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20883 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20885 CompileRun("x1 = x2 = 0;");
20886 rr = v8::Promise::Resolver::New(isolate);
20887 rr->GetPromise()->Catch(f1)->Chain(f2);
20888 rr->Reject(v8::Integer::New(isolate, 3));
20889 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20890 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20891 isolate->RunMicrotasks();
20892 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20893 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20897 TEST(PromiseThen) {
20898 LocalContext context;
20899 v8::Isolate* isolate = context->GetIsolate();
20900 v8::HandleScope scope(isolate);
20901 Handle<Object> global = context->Global();
20904 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
20905 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
20906 Handle<v8::Promise> p = pr->GetPromise();
20907 Handle<v8::Promise> q = qr->GetPromise();
20909 CHECK(p->IsPromise());
20910 CHECK(q->IsPromise());
20912 pr->Resolve(v8::Integer::New(isolate, 1));
20915 // Chaining non-pending promises.
20919 "function f1(x) { x1 = x; return x+1 };\n"
20920 "function f2(x) { x2 = x; return x+1 };\n");
20921 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
20922 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
20926 CHECK(global->Get(v8_str("x1"))->IsNumber());
20927 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20928 isolate->RunMicrotasks();
20929 CHECK(!global->Get(v8_str("x1"))->IsNumber());
20930 CHECK(p->Equals(global->Get(v8_str("x1"))));
20933 CompileRun("x1 = x2 = 0;");
20935 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20936 isolate->RunMicrotasks();
20937 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
20940 CompileRun("x1 = x2 = 0;");
20941 pr = v8::Promise::Resolver::New(isolate);
20942 qr = v8::Promise::Resolver::New(isolate);
20945 qr->GetPromise()->Then(f1)->Then(f2);
20947 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20948 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20949 isolate->RunMicrotasks();
20950 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20951 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20953 pr->Resolve(v8::Integer::New(isolate, 3));
20955 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
20956 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
20957 isolate->RunMicrotasks();
20958 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
20959 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
20963 TEST(DisallowJavascriptExecutionScope) {
20964 LocalContext context;
20965 v8::Isolate* isolate = context->GetIsolate();
20966 v8::HandleScope scope(isolate);
20967 v8::Isolate::DisallowJavascriptExecutionScope no_js(
20968 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20973 TEST(AllowJavascriptExecutionScope) {
20974 LocalContext context;
20975 v8::Isolate* isolate = context->GetIsolate();
20976 v8::HandleScope scope(isolate);
20977 v8::Isolate::DisallowJavascriptExecutionScope no_js(
20978 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
20979 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20980 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20981 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
20987 TEST(ThrowOnJavascriptExecution) {
20988 LocalContext context;
20989 v8::Isolate* isolate = context->GetIsolate();
20990 v8::HandleScope scope(isolate);
20991 v8::TryCatch try_catch;
20992 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
20993 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
20995 CHECK(try_catch.HasCaught());
20999 TEST(Regress354123) {
21000 LocalContext current;
21001 v8::Isolate* isolate = current->GetIsolate();
21002 v8::HandleScope scope(isolate);
21004 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
21005 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
21006 current->Global()->Set(v8_str("friend"), templ->NewInstance());
21008 // Test access using __proto__ from the prototype chain.
21009 named_access_count = 0;
21010 CompileRun("friend.__proto__ = {};");
21011 CHECK_EQ(2, named_access_count);
21012 CompileRun("friend.__proto__;");
21013 CHECK_EQ(4, named_access_count);
21015 // Test access using __proto__ as a hijacked function (A).
21016 named_access_count = 0;
21017 CompileRun("var p = Object.prototype;"
21018 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
21019 "f.call(friend, {});");
21020 CHECK_EQ(1, named_access_count);
21021 CompileRun("var p = Object.prototype;"
21022 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
21023 "f.call(friend);");
21024 CHECK_EQ(2, named_access_count);
21026 // Test access using __proto__ as a hijacked function (B).
21027 named_access_count = 0;
21028 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
21029 "f.call(friend, {});");
21030 CHECK_EQ(1, named_access_count);
21031 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
21032 "f.call(friend);");
21033 CHECK_EQ(2, named_access_count);
21035 // Test access using Object.setPrototypeOf reflective method.
21036 named_access_count = 0;
21037 CompileRun("Object.setPrototypeOf(friend, {});");
21038 CHECK_EQ(1, named_access_count);
21039 CompileRun("Object.getPrototypeOf(friend);");
21040 CHECK_EQ(2, named_access_count);
21044 TEST(CaptureStackTraceForStackOverflow) {
21045 v8::internal::FLAG_stack_size = 150;
21046 LocalContext current;
21047 v8::Isolate* isolate = current->GetIsolate();
21048 v8::HandleScope scope(isolate);
21049 V8::SetCaptureStackTraceForUncaughtExceptions(
21050 true, 10, v8::StackTrace::kDetailed);
21051 v8::TryCatch try_catch;
21052 CompileRun("(function f(x) { f(x+1); })(0)");
21053 CHECK(try_catch.HasCaught());
21057 TEST(ScriptNameAndLineNumber) {
21059 v8::Isolate* isolate = env->GetIsolate();
21060 v8::HandleScope scope(isolate);
21061 const char* url = "http://www.foo.com/foo.js";
21062 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
21063 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
21064 Local<Script> script = v8::ScriptCompiler::Compile(
21065 isolate, &script_source);
21066 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
21067 CHECK(!script_name.IsEmpty());
21068 CHECK(script_name->IsString());
21069 String::Utf8Value utf8_name(script_name);
21070 CHECK_EQ(0, strcmp(url, *utf8_name));
21071 int line_number = script->GetUnboundScript()->GetLineNumber(0);
21072 CHECK_EQ(13, line_number);
21075 void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
21076 const char* expected_source_mapping_url) {
21077 if (expected_source_url != NULL) {
21078 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
21079 CHECK_EQ(0, strcmp(expected_source_url, *url));
21081 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
21083 if (expected_source_mapping_url != NULL) {
21084 v8::String::Utf8Value url(
21085 script->GetUnboundScript()->GetSourceMappingURL());
21086 CHECK_EQ(0, strcmp(expected_source_mapping_url, *url));
21088 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
21092 void SourceURLHelper(const char* source, const char* expected_source_url,
21093 const char* expected_source_mapping_url) {
21094 Local<Script> script = v8_compile(source);
21095 CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
21099 TEST(ScriptSourceURLAndSourceMappingURL) {
21101 v8::Isolate* isolate = env->GetIsolate();
21102 v8::HandleScope scope(isolate);
21103 SourceURLHelper("function foo() {}\n"
21104 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
21105 SourceURLHelper("function foo() {}\n"
21106 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
21108 // Both sourceURL and sourceMappingURL.
21109 SourceURLHelper("function foo() {}\n"
21110 "//# sourceURL=bar3.js\n"
21111 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
21113 // Two source URLs; the first one is ignored.
21114 SourceURLHelper("function foo() {}\n"
21115 "//# sourceURL=ignoreme.js\n"
21116 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
21117 SourceURLHelper("function foo() {}\n"
21118 "//# sourceMappingURL=ignoreme.js\n"
21119 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
21121 // SourceURL or sourceMappingURL in the middle of the script.
21122 SourceURLHelper("function foo() {}\n"
21123 "//# sourceURL=bar7.js\n"
21124 "function baz() {}\n", "bar7.js", NULL);
21125 SourceURLHelper("function foo() {}\n"
21126 "//# sourceMappingURL=bar8.js\n"
21127 "function baz() {}\n", NULL, "bar8.js");
21129 // Too much whitespace.
21130 SourceURLHelper("function foo() {}\n"
21131 "//# sourceURL=bar9.js\n"
21132 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
21133 SourceURLHelper("function foo() {}\n"
21134 "//# sourceURL =bar11.js\n"
21135 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
21137 // Disallowed characters in value.
21138 SourceURLHelper("function foo() {}\n"
21139 "//# sourceURL=bar13 .js \n"
21140 "//# sourceMappingURL=bar14 .js \n",
21142 SourceURLHelper("function foo() {}\n"
21143 "//# sourceURL=bar15\t.js \n"
21144 "//# sourceMappingURL=bar16\t.js \n",
21146 SourceURLHelper("function foo() {}\n"
21147 "//# sourceURL=bar17'.js \n"
21148 "//# sourceMappingURL=bar18'.js \n",
21150 SourceURLHelper("function foo() {}\n"
21151 "//# sourceURL=bar19\".js \n"
21152 "//# sourceMappingURL=bar20\".js \n",
21155 // Not too much whitespace.
21156 SourceURLHelper("function foo() {}\n"
21157 "//# sourceURL= bar21.js \n"
21158 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
21162 TEST(GetOwnPropertyDescriptor) {
21164 v8::Isolate* isolate = env->GetIsolate();
21165 v8::HandleScope scope(isolate);
21167 "var x = { value : 13};"
21168 "Object.defineProperty(x, 'p0', {value : 12});"
21169 "Object.defineProperty(x, 'p1', {"
21170 " set : function(value) { this.value = value; },"
21171 " get : function() { return this.value; },"
21173 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
21174 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
21175 CHECK(desc->IsUndefined());
21176 desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
21177 CHECK(v8_num(12)->Equals(Local<Object>::Cast(desc)->Get(v8_str("value"))));
21178 desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
21179 Local<Function> set =
21180 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
21181 Local<Function> get =
21182 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
21183 CHECK(v8_num(13)->Equals(get->Call(x, 0, NULL)));
21184 Handle<Value> args[] = { v8_num(14) };
21185 set->Call(x, 1, args);
21186 CHECK(v8_num(14)->Equals(get->Call(x, 0, NULL)));
21190 TEST(Regress411877) {
21191 v8::Isolate* isolate = CcTest::isolate();
21192 v8::HandleScope handle_scope(isolate);
21193 v8::Handle<v8::ObjectTemplate> object_template =
21194 v8::ObjectTemplate::New(isolate);
21195 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
21196 IndexedAccessCounter);
21198 v8::Handle<Context> context = Context::New(isolate);
21199 v8::Context::Scope context_scope(context);
21201 context->Global()->Set(v8_str("o"), object_template->NewInstance());
21202 CompileRun("Object.getOwnPropertyNames(o)");
21206 TEST(GetHiddenPropertyTableAfterAccessCheck) {
21207 v8::Isolate* isolate = CcTest::isolate();
21208 v8::HandleScope handle_scope(isolate);
21209 v8::Handle<v8::ObjectTemplate> object_template =
21210 v8::ObjectTemplate::New(isolate);
21211 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
21212 IndexedAccessCounter);
21214 v8::Handle<Context> context = Context::New(isolate);
21215 v8::Context::Scope context_scope(context);
21217 v8::Handle<v8::Object> obj = object_template->NewInstance();
21218 obj->Set(v8_str("key"), v8_str("value"));
21219 obj->Delete(v8_str("key"));
21221 obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
21225 TEST(Regress411793) {
21226 v8::Isolate* isolate = CcTest::isolate();
21227 v8::HandleScope handle_scope(isolate);
21228 v8::Handle<v8::ObjectTemplate> object_template =
21229 v8::ObjectTemplate::New(isolate);
21230 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
21231 IndexedAccessCounter);
21233 v8::Handle<Context> context = Context::New(isolate);
21234 v8::Context::Scope context_scope(context);
21236 context->Global()->Set(v8_str("o"), object_template->NewInstance());
21238 "Object.defineProperty(o, 'key', "
21239 " { get: function() {}, set: function() {} });");
21242 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
21244 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
21246 virtual size_t GetMoreData(const uint8_t** src) {
21247 // Unlike in real use cases, this function will never block.
21248 if (chunks_[index_] == NULL) {
21251 // Copy the data, since the caller takes ownership of it.
21252 size_t len = strlen(chunks_[index_]);
21253 // We don't need to zero-terminate since we return the length.
21254 uint8_t* copy = new uint8_t[len];
21255 memcpy(copy, chunks_[index_], len);
21261 // Helper for constructing a string from chunks (the compilation needs it
21263 static char* FullSourceString(const char** chunks) {
21264 size_t total_len = 0;
21265 for (size_t i = 0; chunks[i] != NULL; ++i) {
21266 total_len += strlen(chunks[i]);
21268 char* full_string = new char[total_len + 1];
21270 for (size_t i = 0; chunks[i] != NULL; ++i) {
21271 size_t len = strlen(chunks[i]);
21272 memcpy(full_string + offset, chunks[i], len);
21275 full_string[total_len] = 0;
21276 return full_string;
21280 const char** chunks_;
21285 // Helper function for running streaming tests.
21286 void RunStreamingTest(const char** chunks,
21287 v8::ScriptCompiler::StreamedSource::Encoding encoding =
21288 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
21289 bool expected_success = true,
21290 const char* expected_source_url = NULL,
21291 const char* expected_source_mapping_url = NULL) {
21293 v8::Isolate* isolate = env->GetIsolate();
21294 v8::HandleScope scope(isolate);
21295 v8::TryCatch try_catch;
21297 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
21299 v8::ScriptCompiler::ScriptStreamingTask* task =
21300 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
21302 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
21303 // task here in the main thread.
21307 // Possible errors are only produced while compiling.
21308 CHECK_EQ(false, try_catch.HasCaught());
21310 v8::ScriptOrigin origin(v8_str("http://foo.com"));
21311 char* full_source = TestSourceStream::FullSourceString(chunks);
21312 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
21313 isolate, &source, v8_str(full_source), origin);
21314 if (expected_success) {
21315 CHECK(!script.IsEmpty());
21316 v8::Handle<Value> result(script->Run());
21317 // All scripts are supposed to return the fixed value 13 when ran.
21318 CHECK_EQ(13, result->Int32Value());
21319 CheckMagicComments(script, expected_source_url,
21320 expected_source_mapping_url);
21322 CHECK(script.IsEmpty());
21323 CHECK(try_catch.HasCaught());
21325 delete[] full_source;
21329 TEST(StreamingSimpleScript) {
21330 // This script is unrealistically small, since no one chunk is enough to fill
21331 // the backing buffer of Scanner, let alone overflow it.
21332 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
21334 RunStreamingTest(chunks);
21338 TEST(StreamingBiggerScript) {
21339 const char* chunk1 =
21340 "function foo() {\n"
21341 " // Make this chunk sufficiently long so that it will overflow the\n"
21342 " // backing buffer of the Scanner.\n"
21344 " var result = 0;\n"
21345 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21347 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21349 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21351 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
21352 " return result;\n"
21354 const char* chunks[] = {chunk1, "foo(); ", NULL};
21355 RunStreamingTest(chunks);
21359 TEST(StreamingScriptWithParseError) {
21360 // Test that parse errors from streamed scripts are propagated correctly.
21363 " // This will result in a parse error.\n"
21364 " var if else then foo";
21365 char chunk2[] = " 13\n";
21366 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21368 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
21371 // Test that the next script succeeds normally.
21374 " // This will be parsed successfully.\n"
21375 " function foo() { return ";
21376 char chunk2[] = " 13; }\n";
21377 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21379 RunStreamingTest(chunks);
21384 TEST(StreamingUtf8Script) {
21385 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
21387 const char* chunk1 =
21388 "function foo() {\n"
21389 " // This function will contain an UTF-8 character which is not in\n"
21391 " var foob\xec\x92\x81r = 13;\n"
21392 " return foob\xec\x92\x81r;\n"
21394 const char* chunks[] = {chunk1, "foo(); ", NULL};
21395 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21399 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
21400 // A sanity check to prove that the approach of splitting UTF-8
21401 // characters is correct. Here is an UTF-8 character which will take three
21403 const char* reference = "\xec\x92\x81";
21404 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
21407 "function foo() {\n"
21408 " // This function will contain an UTF-8 character which is not in\n"
21413 " return foob\xec\x92\x81r;\n"
21415 for (int i = 0; i < 3; ++i) {
21416 chunk2[i] = reference[i];
21418 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21419 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21423 TEST(StreamingUtf8ScriptWithSplitCharacters) {
21424 // Stream data where a multi-byte UTF-8 character is split between two data
21426 const char* reference = "\xec\x92\x81";
21428 "function foo() {\n"
21429 " // This function will contain an UTF-8 character which is not in\n"
21434 " return foob\xec\x92\x81r;\n"
21436 chunk1[strlen(chunk1) - 1] = reference[0];
21437 chunk2[0] = reference[1];
21438 chunk2[1] = reference[2];
21439 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21440 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21444 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
21445 // Tests edge cases which should still be decoded correctly.
21447 // Case 1: a chunk contains only bytes for a split character (and no other
21448 // data). This kind of a chunk would be exceptionally small, but we should
21449 // still decode it correctly.
21450 const char* reference = "\xec\x92\x81";
21451 // The small chunk is at the beginning of the split character
21454 "function foo() {\n"
21455 " // This function will contain an UTF-8 character which is not in\n"
21458 char chunk2[] = "XX";
21461 " return foob\xec\x92\x81r;\n"
21463 chunk2[0] = reference[0];
21464 chunk2[1] = reference[1];
21465 chunk3[0] = reference[2];
21466 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
21467 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21469 // The small chunk is at the end of a character
21472 "function foo() {\n"
21473 " // This function will contain an UTF-8 character which is not in\n"
21476 char chunk2[] = "XX";
21479 " return foob\xec\x92\x81r;\n"
21481 chunk1[strlen(chunk1) - 1] = reference[0];
21482 chunk2[0] = reference[1];
21483 chunk2[1] = reference[2];
21484 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
21485 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21487 // Case 2: the script ends with a multi-byte character. Make sure that it's
21488 // decoded correctly and not just ignored.
21491 "var foob\xec\x92\x81 = 13;\n"
21492 "foob\xec\x92\x81";
21493 const char* chunks[] = {chunk1, NULL};
21494 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21499 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
21500 // Test cases where a UTF-8 character is split over several chunks. Those
21501 // cases are not supported (the embedder should give the data in big enough
21502 // chunks), but we shouldn't crash, just produce a parse error.
21503 const char* reference = "\xec\x92\x81";
21505 "function foo() {\n"
21506 " // This function will contain an UTF-8 character which is not in\n"
21509 char chunk2[] = "X";
21512 " return foob\xec\x92\x81r;\n"
21514 chunk1[strlen(chunk1) - 1] = reference[0];
21515 chunk2[0] = reference[1];
21516 chunk3[0] = reference[2];
21517 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
21519 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
21523 TEST(StreamingProducesParserCache) {
21524 i::FLAG_min_preparse_length = 0;
21525 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
21529 v8::Isolate* isolate = env->GetIsolate();
21530 v8::HandleScope scope(isolate);
21532 v8::ScriptCompiler::StreamedSource source(
21533 new TestSourceStream(chunks),
21534 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21535 v8::ScriptCompiler::ScriptStreamingTask* task =
21536 v8::ScriptCompiler::StartStreamingScript(
21537 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
21539 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
21540 // task here in the main thread.
21544 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
21545 CHECK(cached_data != NULL);
21546 CHECK(cached_data->data != NULL);
21547 CHECK(!cached_data->rejected);
21548 CHECK_GT(cached_data->length, 0);
21552 TEST(StreamingWithDebuggingDoesNotProduceParserCache) {
21553 // If the debugger is active, we should just not produce parser cache at
21554 // all. This is a regeression test: We used to produce a parser cache without
21555 // any data in it (just headers).
21556 i::FLAG_min_preparse_length = 0;
21557 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
21561 v8::Isolate* isolate = env->GetIsolate();
21562 v8::HandleScope scope(isolate);
21564 // Make the debugger active by setting a breakpoint.
21565 CompileRun("function break_here() { }");
21566 i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(
21567 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("break_here"))));
21568 v8::internal::Debug* debug = CcTest::i_isolate()->debug();
21570 debug->SetBreakPoint(func, i::Handle<i::Object>(v8::internal::Smi::FromInt(1),
21571 CcTest::i_isolate()),
21574 v8::ScriptCompiler::StreamedSource source(
21575 new TestSourceStream(chunks),
21576 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21577 v8::ScriptCompiler::ScriptStreamingTask* task =
21578 v8::ScriptCompiler::StartStreamingScript(
21579 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
21581 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
21582 // task here in the main thread.
21586 // Check that we got no cached data.
21587 CHECK(source.GetCachedData() == NULL);
21591 TEST(StreamingScriptWithInvalidUtf8) {
21592 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
21593 // chunk don't produce a crash.
21594 const char* reference = "\xec\x92\x81\x80\x80";
21596 "function foo() {\n"
21597 " // This function will contain an UTF-8 character which is not in\n"
21599 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
21602 " return foob\xec\x92\x81\x80\x80r;\n"
21604 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
21606 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21607 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
21611 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
21612 // Regression test: Stream data where there are several multi-byte UTF-8
21613 // characters in a sequence and one of them is split between two data chunks.
21614 const char* reference = "\xec\x92\x81";
21616 "function foo() {\n"
21617 " // This function will contain an UTF-8 character which is not in\n"
21619 " var foob\xec\x92\x81X";
21622 " return foob\xec\x92\x81\xec\x92\x81r;\n"
21624 chunk1[strlen(chunk1) - 1] = reference[0];
21625 chunk2[0] = reference[1];
21626 chunk2[1] = reference[2];
21627 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21628 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21632 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
21633 // Another regression test, similar to the previous one. The difference is
21634 // that the split character is not the last one in the sequence.
21635 const char* reference = "\xec\x92\x81";
21637 "function foo() {\n"
21638 " // This function will contain an UTF-8 character which is not in\n"
21642 "XX\xec\x92\x81r = 13;\n"
21643 " return foob\xec\x92\x81\xec\x92\x81r;\n"
21645 chunk1[strlen(chunk1) - 1] = reference[0];
21646 chunk2[0] = reference[1];
21647 chunk2[1] = reference[2];
21648 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
21649 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
21653 TEST(StreamingWithHarmonyScopes) {
21654 // Don't use RunStreamingTest here so that both scripts get to use the same
21655 // LocalContext and HandleScope.
21657 v8::Isolate* isolate = env->GetIsolate();
21658 v8::HandleScope scope(isolate);
21660 // First, run a script with a let variable.
21661 CompileRun("\"use strict\"; let x = 1;");
21663 // Then stream a script which (erroneously) tries to introduce the same
21665 const char* chunks[] = {"\"use strict\"; let x = 2;", NULL};
21667 v8::TryCatch try_catch;
21668 v8::ScriptCompiler::StreamedSource source(
21669 new TestSourceStream(chunks),
21670 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
21671 v8::ScriptCompiler::ScriptStreamingTask* task =
21672 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
21676 // Parsing should succeed (the script will be parsed and compiled in a context
21677 // independent way, so the error is not detected).
21678 CHECK_EQ(false, try_catch.HasCaught());
21680 v8::ScriptOrigin origin(v8_str("http://foo.com"));
21681 char* full_source = TestSourceStream::FullSourceString(chunks);
21682 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
21683 isolate, &source, v8_str(full_source), origin);
21684 CHECK(!script.IsEmpty());
21685 CHECK_EQ(false, try_catch.HasCaught());
21687 // Running the script exposes the error.
21688 v8::Handle<Value> result(script->Run());
21689 CHECK(result.IsEmpty());
21690 CHECK(try_catch.HasCaught());
21691 delete[] full_source;
21695 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
21696 const char* garbage = "garbage garbage garbage garbage garbage garbage";
21697 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
21699 v8::ScriptCompiler::CachedData* cached_data =
21700 new v8::ScriptCompiler::CachedData(data, length);
21701 DCHECK(!cached_data->rejected);
21702 v8::ScriptOrigin origin(v8_str("origin"));
21703 v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
21704 v8::Handle<v8::Script> script =
21705 v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
21706 CHECK(cached_data->rejected);
21707 CHECK_EQ(42, script->Run()->Int32Value());
21711 TEST(InvalidCacheData) {
21712 v8::V8::Initialize();
21713 v8::HandleScope scope(CcTest::isolate());
21714 LocalContext context;
21715 TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
21716 TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
21720 TEST(ParserCacheRejectedGracefully) {
21721 i::FLAG_min_preparse_length = 0;
21722 v8::V8::Initialize();
21723 v8::HandleScope scope(CcTest::isolate());
21724 LocalContext context;
21725 // Produce valid cached data.
21726 v8::ScriptOrigin origin(v8_str("origin"));
21727 v8::Local<v8::String> source_str = v8_str("function foo() {}");
21728 v8::ScriptCompiler::Source source(source_str, origin);
21729 v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
21730 CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
21731 CHECK(!script.IsEmpty());
21732 const v8::ScriptCompiler::CachedData* original_cached_data =
21733 source.GetCachedData();
21734 CHECK(original_cached_data != NULL);
21735 CHECK(original_cached_data->data != NULL);
21736 CHECK(!original_cached_data->rejected);
21737 CHECK_GT(original_cached_data->length, 0);
21738 // Recompiling the same script with it won't reject the data.
21740 v8::ScriptCompiler::Source source_with_cached_data(
21741 source_str, origin,
21742 new v8::ScriptCompiler::CachedData(original_cached_data->data,
21743 original_cached_data->length));
21744 v8::Handle<v8::Script> script =
21745 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21746 v8::ScriptCompiler::kConsumeParserCache);
21747 CHECK(!script.IsEmpty());
21748 const v8::ScriptCompiler::CachedData* new_cached_data =
21749 source_with_cached_data.GetCachedData();
21750 CHECK(new_cached_data != NULL);
21751 CHECK(!new_cached_data->rejected);
21753 // Compile an incompatible script with the cached data. The new script doesn't
21754 // have the same starting position for the function as the old one, so the old
21755 // cached data will be incompatible with it and will be rejected.
21757 v8::Local<v8::String> incompatible_source_str =
21758 v8_str(" function foo() {}");
21759 v8::ScriptCompiler::Source source_with_cached_data(
21760 incompatible_source_str, origin,
21761 new v8::ScriptCompiler::CachedData(original_cached_data->data,
21762 original_cached_data->length));
21763 v8::Handle<v8::Script> script =
21764 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
21765 v8::ScriptCompiler::kConsumeParserCache);
21766 CHECK(!script.IsEmpty());
21767 const v8::ScriptCompiler::CachedData* new_cached_data =
21768 source_with_cached_data.GetCachedData();
21769 CHECK(new_cached_data != NULL);
21770 CHECK(new_cached_data->rejected);
21775 TEST(StringConcatOverflow) {
21776 v8::V8::Initialize();
21777 v8::HandleScope scope(CcTest::isolate());
21778 RandomLengthOneByteResource* r =
21779 new RandomLengthOneByteResource(i::String::kMaxLength);
21780 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
21781 CHECK(!str.IsEmpty());
21782 v8::TryCatch try_catch;
21783 v8::Local<v8::String> result = v8::String::Concat(str, str);
21784 CHECK(result.IsEmpty());
21785 CHECK(!try_catch.HasCaught());
21789 TEST(TurboAsmDisablesNeuter) {
21790 v8::V8::Initialize();
21791 v8::HandleScope scope(CcTest::isolate());
21792 LocalContext context;
21793 #if V8_TURBOFAN_TARGET
21794 bool should_be_neuterable = !i::FLAG_turbo_asm;
21796 bool should_be_neuterable = true;
21799 "function Module(stdlib, foreign, heap) {"
21801 " var MEM32 = new stdlib.Int32Array(heap);"
21802 " function load() { return MEM32[0]; }"
21803 " return { load: load };"
21805 "var buffer = new ArrayBuffer(4);"
21806 "Module(this, {}, buffer).load();"
21809 v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
21810 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21812 const char* store =
21813 "function Module(stdlib, foreign, heap) {"
21815 " var MEM32 = new stdlib.Int32Array(heap);"
21816 " function store() { MEM32[0] = 0; }"
21817 " return { store: store };"
21819 "var buffer = new ArrayBuffer(4);"
21820 "Module(this, {}, buffer).store();"
21823 result = CompileRun(store).As<v8::ArrayBuffer>();
21824 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
21828 TEST(GetPrototypeAccessControl) {
21829 i::FLAG_allow_natives_syntax = true;
21830 v8::Isolate* isolate = CcTest::isolate();
21831 v8::HandleScope handle_scope(isolate);
21834 v8::Handle<v8::ObjectTemplate> obj_template =
21835 v8::ObjectTemplate::New(isolate);
21836 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
21837 BlockEverythingIndexed);
21839 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
21842 v8::TryCatch try_catch;
21844 "function f() { %_GetPrototype(prohibited); }"
21845 "%OptimizeFunctionOnNextCall(f);"
21847 CHECK(try_catch.HasCaught());
21852 TEST(GetPrototypeHidden) {
21853 i::FLAG_allow_natives_syntax = true;
21854 v8::Isolate* isolate = CcTest::isolate();
21855 v8::HandleScope handle_scope(isolate);
21858 Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
21859 t->SetHiddenPrototype(true);
21860 Handle<Object> proto = t->GetFunction()->NewInstance();
21861 Handle<Object> object = Object::New(isolate);
21862 Handle<Object> proto2 = Object::New(isolate);
21863 object->SetPrototype(proto);
21864 proto->SetPrototype(proto2);
21866 env->Global()->Set(v8_str("object"), object);
21867 env->Global()->Set(v8_str("proto"), proto);
21868 env->Global()->Set(v8_str("proto2"), proto2);
21870 v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
21871 CHECK(result->Equals(proto2));
21873 result = CompileRun(
21874 "function f() { return %_GetPrototype(object); }"
21875 "%OptimizeFunctionOnNextCall(f);"
21877 CHECK(result->Equals(proto2));
21881 TEST(ClassPrototypeCreationContext) {
21882 i::FLAG_harmony_classes = true;
21883 v8::Isolate* isolate = CcTest::isolate();
21884 v8::HandleScope handle_scope(isolate);
21887 Handle<Object> result = Handle<Object>::Cast(
21888 CompileRun("'use strict'; class Example { }; Example.prototype"));
21889 CHECK(env.local() == result->CreationContext());
21893 TEST(SimpleStreamingScriptWithSourceURL) {
21894 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
21895 "//# sourceURL=bar2.js\n", NULL};
21896 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21901 TEST(StreamingScriptWithSplitSourceURL) {
21902 const char* chunks[] = {"function foo() { ret", "urn 13; } f",
21903 "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
21904 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
21909 TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
21910 const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
21911 " sourceMappingURL=bar2.js\n", "foo();", NULL};
21912 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
21917 TEST(NewStringRangeError) {
21918 v8::Isolate* isolate = CcTest::isolate();
21919 v8::HandleScope handle_scope(isolate);
21921 const int length = i::String::kMaxLength + 1;
21922 const int buffer_size = length * sizeof(uint16_t);
21923 void* buffer = malloc(buffer_size);
21924 if (buffer == NULL) return;
21925 memset(buffer, 'A', buffer_size);
21927 v8::TryCatch try_catch;
21928 char* data = reinterpret_cast<char*>(buffer);
21929 CHECK(v8::String::NewFromUtf8(isolate, data, v8::String::kNormalString,
21930 length).IsEmpty());
21931 CHECK(try_catch.HasCaught());
21934 v8::TryCatch try_catch;
21935 uint8_t* data = reinterpret_cast<uint8_t*>(buffer);
21936 CHECK(v8::String::NewFromOneByte(isolate, data, v8::String::kNormalString,
21937 length).IsEmpty());
21938 CHECK(try_catch.HasCaught());
21941 v8::TryCatch try_catch;
21942 uint16_t* data = reinterpret_cast<uint16_t*>(buffer);
21943 CHECK(v8::String::NewFromTwoByte(isolate, data, v8::String::kNormalString,
21944 length).IsEmpty());
21945 CHECK(try_catch.HasCaught());
21951 TEST(SealHandleScope) {
21952 v8::Isolate* isolate = CcTest::isolate();
21953 v8::HandleScope handle_scope(isolate);
21956 v8::SealHandleScope seal(isolate);
21959 v8::Local<v8::Object> obj = v8::Object::New(isolate);
21965 TEST(SealHandleScopeNested) {
21966 v8::Isolate* isolate = CcTest::isolate();
21967 v8::HandleScope handle_scope(isolate);
21970 v8::SealHandleScope seal(isolate);
21973 v8::HandleScope handle_scope(isolate);
21976 v8::Local<v8::Object> obj = v8::Object::New(isolate);