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.
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/cpu-profiler.h"
45 #include "src/execution.h"
46 #include "src/isolate.h"
47 #include "src/objects.h"
48 #include "src/parser.h"
49 #include "src/snapshot.h"
50 #include "src/unicode-inl.h"
51 #include "src/utils.h"
52 #include "src/vm-state.h"
53 #include "test/cctest/cctest.h"
55 static const bool kLogThreading = false;
58 using ::v8::BooleanObject;
60 using ::v8::Extension;
62 using ::v8::FunctionTemplate;
64 using ::v8::HandleScope;
68 using ::v8::MessageCallback;
70 using ::v8::ObjectTemplate;
71 using ::v8::Persistent;
73 using ::v8::StackTrace;
77 using ::v8::Undefined;
83 #define THREADED_PROFILED_TEST(Name) \
84 static void Test##Name(); \
85 TEST(Name##WithProfiler) { \
86 RunWithProfiler(&Test##Name); \
91 void RunWithProfiler(void (*test)()) {
93 v8::HandleScope scope(env->GetIsolate());
94 v8::Local<v8::String> profile_name =
95 v8::String::NewFromUtf8(env->GetIsolate(), "my_profile1");
96 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
98 cpu_profiler->StartProfiling(profile_name);
100 reinterpret_cast<i::CpuProfiler*>(cpu_profiler)->DeleteAllProfiles();
104 static int signature_callback_count;
105 static Local<Value> signature_expected_receiver;
106 static void IncrementingSignatureCallback(
107 const v8::FunctionCallbackInfo<v8::Value>& args) {
108 ApiTestFuzzer::Fuzz();
109 signature_callback_count++;
110 CHECK_EQ(signature_expected_receiver, args.Holder());
111 CHECK_EQ(signature_expected_receiver, args.This());
112 v8::Handle<v8::Array> result =
113 v8::Array::New(args.GetIsolate(), args.Length());
114 for (int i = 0; i < args.Length(); i++)
115 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
116 args.GetReturnValue().Set(result);
120 static void SignatureCallback(
121 const v8::FunctionCallbackInfo<v8::Value>& args) {
122 ApiTestFuzzer::Fuzz();
123 v8::Handle<v8::Array> result =
124 v8::Array::New(args.GetIsolate(), args.Length());
125 for (int i = 0; i < args.Length(); i++) {
126 result->Set(v8::Integer::New(args.GetIsolate(), i), args[i]);
128 args.GetReturnValue().Set(result);
132 // Tests that call v8::V8::Dispose() cannot be threaded.
133 UNINITIALIZED_TEST(InitializeAndDisposeOnce) {
134 CHECK(v8::V8::Initialize());
135 CHECK(v8::V8::Dispose());
139 // Tests that call v8::V8::Dispose() cannot be threaded.
140 UNINITIALIZED_TEST(InitializeAndDisposeMultiple) {
141 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
142 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
143 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
144 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Initialize());
145 for (int i = 0; i < 3; ++i) CHECK(v8::V8::Dispose());
149 THREADED_TEST(Handles) {
150 v8::HandleScope scope(CcTest::isolate());
151 Local<Context> local_env;
154 local_env = env.local();
157 // Local context should still be live.
158 CHECK(!local_env.IsEmpty());
161 v8::Handle<v8::Primitive> undef = v8::Undefined(CcTest::isolate());
162 CHECK(!undef.IsEmpty());
163 CHECK(undef->IsUndefined());
165 const char* source = "1 + 2 + 3";
166 Local<Script> script = v8_compile(source);
167 CHECK_EQ(6, script->Run()->Int32Value());
173 THREADED_TEST(IsolateOfContext) {
174 v8::HandleScope scope(CcTest::isolate());
175 v8::Handle<Context> env = Context::New(CcTest::isolate());
177 CHECK(!env->GetIsolate()->InContext());
178 CHECK(env->GetIsolate() == CcTest::isolate());
180 CHECK(env->GetIsolate()->InContext());
181 CHECK(env->GetIsolate() == CcTest::isolate());
183 CHECK(!env->GetIsolate()->InContext());
184 CHECK(env->GetIsolate() == CcTest::isolate());
188 static void TestSignature(const char* loop_js, Local<Value> receiver,
189 v8::Isolate* isolate) {
190 i::ScopedVector<char> source(200);
192 "for (var i = 0; i < 10; i++) {"
196 signature_callback_count = 0;
197 signature_expected_receiver = receiver;
198 bool expected_to_throw = receiver.IsEmpty();
199 v8::TryCatch try_catch;
200 CompileRun(source.start());
201 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
202 if (!expected_to_throw) {
203 CHECK_EQ(10, signature_callback_count);
205 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
206 try_catch.Exception()->ToString(isolate));
211 THREADED_TEST(ReceiverSignature) {
213 v8::Isolate* isolate = env->GetIsolate();
214 v8::HandleScope scope(isolate);
216 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
217 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
218 v8::Handle<v8::FunctionTemplate> callback_sig =
219 v8::FunctionTemplate::New(
220 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
221 v8::Handle<v8::FunctionTemplate> callback =
222 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
223 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
224 sub_fun->Inherit(fun);
225 v8::Handle<v8::FunctionTemplate> unrel_fun =
226 v8::FunctionTemplate::New(isolate);
227 // Install properties.
228 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
229 fun_proto->Set(v8_str("prop_sig"), callback_sig);
230 fun_proto->Set(v8_str("prop"), callback);
231 fun_proto->SetAccessorProperty(
232 v8_str("accessor_sig"), callback_sig, callback_sig);
233 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
234 // Instantiate templates.
235 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
236 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
237 // Setup global variables.
238 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
239 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
240 env->Global()->Set(v8_str("fun_instance"), fun_instance);
241 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
243 "var accessor_sig_key = 'accessor_sig';"
244 "var accessor_key = 'accessor';"
245 "var prop_sig_key = 'prop_sig';"
246 "var prop_key = 'prop';"
248 "function copy_props(obj) {"
249 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
250 " var source = Fun.prototype;"
251 " for (var i in keys) {"
252 " var key = keys[i];"
253 " var desc = Object.getOwnPropertyDescriptor(source, key);"
254 " Object.defineProperty(obj, key, desc);"
260 "var unrel = new UnrelFun();"
261 "copy_props(unrel);");
262 // Test with and without ICs
263 const char* test_objects[] = {
264 "fun_instance", "sub_fun_instance", "obj", "unrel" };
265 unsigned bad_signature_start_offset = 2;
266 for (unsigned i = 0; i < arraysize(test_objects); i++) {
267 i::ScopedVector<char> source(200);
269 source, "var test_object = %s; test_object", test_objects[i]);
270 Local<Value> test_object = CompileRun(source.start());
271 TestSignature("test_object.prop();", test_object, isolate);
272 TestSignature("test_object.accessor;", test_object, isolate);
273 TestSignature("test_object[accessor_key];", test_object, isolate);
274 TestSignature("test_object.accessor = 1;", test_object, isolate);
275 TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
276 if (i >= bad_signature_start_offset) test_object = Local<Value>();
277 TestSignature("test_object.prop_sig();", test_object, isolate);
278 TestSignature("test_object.accessor_sig;", test_object, isolate);
279 TestSignature("test_object[accessor_sig_key];", test_object, isolate);
280 TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
281 TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
286 THREADED_TEST(ArgumentSignature) {
288 v8::Isolate* isolate = env->GetIsolate();
289 v8::HandleScope scope(isolate);
290 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
291 cons->SetClassName(v8_str("Cons"));
292 v8::Handle<v8::Signature> sig = v8::Signature::New(
293 isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
294 v8::Handle<v8::FunctionTemplate> fun =
295 v8::FunctionTemplate::New(isolate,
299 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
300 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
302 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
303 CHECK(value1->IsTrue());
305 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
306 CHECK(value2->IsTrue());
308 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
309 CHECK(value3->IsTrue());
311 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
312 cons1->SetClassName(v8_str("Cons1"));
313 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
314 cons2->SetClassName(v8_str("Cons2"));
315 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
316 cons3->SetClassName(v8_str("Cons3"));
318 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
319 v8::Handle<v8::Signature> wsig = v8::Signature::New(
320 isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
321 v8::Handle<v8::FunctionTemplate> fun2 =
322 v8::FunctionTemplate::New(isolate,
327 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
328 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
329 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
330 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
331 v8::Handle<Value> value4 = CompileRun(
332 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
333 "'[object Cons1],[object Cons2],[object Cons3]'");
334 CHECK(value4->IsTrue());
336 v8::Handle<Value> value5 = CompileRun(
337 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
338 CHECK(value5->IsTrue());
340 v8::Handle<Value> value6 = CompileRun(
341 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
342 CHECK(value6->IsTrue());
344 v8::Handle<Value> value7 = CompileRun(
345 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
346 "'[object Cons1],[object Cons2],[object Cons3],d';");
347 CHECK(value7->IsTrue());
349 v8::Handle<Value> value8 = CompileRun(
350 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
351 CHECK(value8->IsTrue());
355 THREADED_TEST(HulIgennem) {
357 v8::Isolate* isolate = env->GetIsolate();
358 v8::HandleScope scope(isolate);
359 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
360 Local<String> undef_str = undef->ToString(isolate);
361 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
362 undef_str->WriteUtf8(value);
363 CHECK_EQ(0, strcmp(value, "undefined"));
364 i::DeleteArray(value);
368 THREADED_TEST(Access) {
370 v8::Isolate* isolate = env->GetIsolate();
371 v8::HandleScope scope(isolate);
372 Local<v8::Object> obj = v8::Object::New(isolate);
373 Local<Value> foo_before = obj->Get(v8_str("foo"));
374 CHECK(foo_before->IsUndefined());
375 Local<String> bar_str = v8_str("bar");
376 obj->Set(v8_str("foo"), bar_str);
377 Local<Value> foo_after = obj->Get(v8_str("foo"));
378 CHECK(!foo_after->IsUndefined());
379 CHECK(foo_after->IsString());
380 CHECK_EQ(bar_str, foo_after);
384 THREADED_TEST(AccessElement) {
386 v8::HandleScope scope(env->GetIsolate());
387 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
388 Local<Value> before = obj->Get(1);
389 CHECK(before->IsUndefined());
390 Local<String> bar_str = v8_str("bar");
391 obj->Set(1, bar_str);
392 Local<Value> after = obj->Get(1);
393 CHECK(!after->IsUndefined());
394 CHECK(after->IsString());
395 CHECK_EQ(bar_str, after);
397 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
398 CHECK_EQ(v8_str("a"), value->Get(0));
399 CHECK_EQ(v8_str("b"), value->Get(1));
403 THREADED_TEST(Script) {
405 v8::HandleScope scope(env->GetIsolate());
406 const char* source = "1 + 2 + 3";
407 Local<Script> script = v8_compile(source);
408 CHECK_EQ(6, script->Run()->Int32Value());
412 class TestResource: public String::ExternalStringResource {
414 explicit TestResource(uint16_t* data, int* counter = NULL,
415 bool owning_data = true)
416 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
417 while (data[length_]) ++length_;
421 if (owning_data_) i::DeleteArray(data_);
422 if (counter_ != NULL) ++*counter_;
425 const uint16_t* data() const {
429 size_t length() const {
441 class TestOneByteResource : public String::ExternalOneByteStringResource {
443 explicit TestOneByteResource(const char* data, int* counter = NULL,
446 data_(data + offset),
447 length_(strlen(data) - offset),
450 ~TestOneByteResource() {
451 i::DeleteArray(orig_data_);
452 if (counter_ != NULL) ++*counter_;
455 const char* data() const {
459 size_t length() const {
464 const char* orig_data_;
471 THREADED_TEST(ScriptUsingStringResource) {
472 int dispose_count = 0;
473 const char* c_source = "1 + 2 * 3";
474 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
477 v8::HandleScope scope(env->GetIsolate());
478 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
479 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
480 Local<Script> script = v8_compile(source);
481 Local<Value> value = script->Run();
482 CHECK(value->IsNumber());
483 CHECK_EQ(7, value->Int32Value());
484 CHECK(source->IsExternal());
486 static_cast<TestResource*>(source->GetExternalStringResource()));
487 String::Encoding encoding = String::UNKNOWN_ENCODING;
488 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
489 source->GetExternalStringResourceBase(&encoding));
490 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
491 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
492 CHECK_EQ(0, dispose_count);
494 CcTest::i_isolate()->compilation_cache()->Clear();
495 CcTest::heap()->CollectAllAvailableGarbage();
496 CHECK_EQ(1, dispose_count);
500 THREADED_TEST(ScriptUsingOneByteStringResource) {
501 int dispose_count = 0;
502 const char* c_source = "1 + 2 * 3";
505 v8::HandleScope scope(env->GetIsolate());
506 TestOneByteResource* resource =
507 new TestOneByteResource(i::StrDup(c_source), &dispose_count);
508 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
509 CHECK(source->IsExternalOneByte());
510 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
511 source->GetExternalOneByteStringResource());
512 String::Encoding encoding = String::UNKNOWN_ENCODING;
513 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
514 source->GetExternalStringResourceBase(&encoding));
515 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
516 Local<Script> script = v8_compile(source);
517 Local<Value> value = script->Run();
518 CHECK(value->IsNumber());
519 CHECK_EQ(7, value->Int32Value());
520 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
521 CHECK_EQ(0, dispose_count);
523 CcTest::i_isolate()->compilation_cache()->Clear();
524 CcTest::heap()->CollectAllAvailableGarbage();
525 CHECK_EQ(1, dispose_count);
529 THREADED_TEST(ScriptMakingExternalString) {
530 int dispose_count = 0;
531 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
534 v8::HandleScope scope(env->GetIsolate());
535 Local<String> source =
536 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
537 // Trigger GCs so that the newly allocated string moves to old gen.
538 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
539 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
540 CHECK_EQ(source->IsExternal(), false);
541 CHECK_EQ(source->IsExternalOneByte(), false);
542 String::Encoding encoding = String::UNKNOWN_ENCODING;
543 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
544 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
545 bool success = source->MakeExternal(new TestResource(two_byte_source,
548 Local<Script> script = v8_compile(source);
549 Local<Value> value = script->Run();
550 CHECK(value->IsNumber());
551 CHECK_EQ(7, value->Int32Value());
552 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
553 CHECK_EQ(0, dispose_count);
555 CcTest::i_isolate()->compilation_cache()->Clear();
556 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
557 CHECK_EQ(1, dispose_count);
561 THREADED_TEST(ScriptMakingExternalOneByteString) {
562 int dispose_count = 0;
563 const char* c_source = "1 + 2 * 3";
566 v8::HandleScope scope(env->GetIsolate());
567 Local<String> source = v8_str(c_source);
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 bool success = source->MakeExternal(
572 new TestOneByteResource(i::StrDup(c_source), &dispose_count));
574 Local<Script> script = v8_compile(source);
575 Local<Value> value = script->Run();
576 CHECK(value->IsNumber());
577 CHECK_EQ(7, value->Int32Value());
578 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
579 CHECK_EQ(0, dispose_count);
581 CcTest::i_isolate()->compilation_cache()->Clear();
582 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
583 CHECK_EQ(1, dispose_count);
587 TEST(MakingExternalStringConditions) {
589 v8::HandleScope scope(env->GetIsolate());
591 // Free some space in the new space so that we can check freshness.
592 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
593 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
595 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
596 Local<String> small_string =
597 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
598 i::DeleteArray(two_byte_string);
600 // We should refuse to externalize newly created small string.
601 CHECK(!small_string->CanMakeExternal());
602 // Trigger GCs so that the newly allocated string moves to old gen.
603 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
604 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
605 // Old space strings should be accepted.
606 CHECK(small_string->CanMakeExternal());
608 two_byte_string = AsciiToTwoByteString("small string 2");
609 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
610 i::DeleteArray(two_byte_string);
612 // We should refuse externalizing newly created small string.
613 CHECK(!small_string->CanMakeExternal());
614 for (int i = 0; i < 100; i++) {
615 String::Value value(small_string);
617 // Frequently used strings should be accepted.
618 CHECK(small_string->CanMakeExternal());
620 const int buf_size = 10 * 1024;
621 char* buf = i::NewArray<char>(buf_size);
622 memset(buf, 'a', buf_size);
623 buf[buf_size - 1] = '\0';
625 two_byte_string = AsciiToTwoByteString(buf);
626 Local<String> large_string =
627 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
629 i::DeleteArray(two_byte_string);
630 // Large strings should be immediately accepted.
631 CHECK(large_string->CanMakeExternal());
635 TEST(MakingExternalOneByteStringConditions) {
637 v8::HandleScope scope(env->GetIsolate());
639 // Free some space in the new space so that we can check freshness.
640 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
641 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
643 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
644 // We should refuse to externalize newly created small string.
645 CHECK(!small_string->CanMakeExternal());
646 // Trigger GCs so that the newly allocated string moves to old gen.
647 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
648 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
649 // Old space strings should be accepted.
650 CHECK(small_string->CanMakeExternal());
652 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
653 // We should refuse externalizing newly created small string.
654 CHECK(!small_string->CanMakeExternal());
655 for (int i = 0; i < 100; i++) {
656 String::Value value(small_string);
658 // Frequently used strings should be accepted.
659 CHECK(small_string->CanMakeExternal());
661 const int buf_size = 10 * 1024;
662 char* buf = i::NewArray<char>(buf_size);
663 memset(buf, 'a', buf_size);
664 buf[buf_size - 1] = '\0';
665 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
667 // Large strings should be immediately accepted.
668 CHECK(large_string->CanMakeExternal());
672 TEST(MakingExternalUnalignedOneByteString) {
674 v8::HandleScope scope(env->GetIsolate());
676 CompileRun("function cons(a, b) { return a + b; }"
677 "function slice(a) { return a.substring(1); }");
678 // Create a cons string that will land in old pointer space.
679 Local<String> cons = Local<String>::Cast(CompileRun(
680 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
681 // Create a sliced string that will land in old pointer space.
682 Local<String> slice = Local<String>::Cast(CompileRun(
683 "slice('abcdefghijklmnopqrstuvwxyz');"));
685 // Trigger GCs so that the newly allocated string moves to old gen.
686 SimulateFullSpace(CcTest::heap()->old_pointer_space());
687 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
688 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
690 // Turn into external string with unaligned resource data.
691 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
693 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
695 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
697 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
700 // Trigger GCs and force evacuation.
701 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
702 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
706 THREADED_TEST(UsingExternalString) {
707 i::Factory* factory = CcTest::i_isolate()->factory();
709 v8::HandleScope scope(CcTest::isolate());
710 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
711 Local<String> string = String::NewExternal(
712 CcTest::isolate(), new TestResource(two_byte_string));
713 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
714 // Trigger GCs so that the newly allocated string moves to old gen.
715 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
716 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
717 i::Handle<i::String> isymbol =
718 factory->InternalizeString(istring);
719 CHECK(isymbol->IsInternalizedString());
721 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
722 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
726 THREADED_TEST(UsingExternalOneByteString) {
727 i::Factory* factory = CcTest::i_isolate()->factory();
729 v8::HandleScope scope(CcTest::isolate());
730 const char* one_byte_string = "test string";
731 Local<String> string = String::NewExternal(
732 CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
733 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
734 // Trigger GCs so that the newly allocated string moves to old gen.
735 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
736 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
737 i::Handle<i::String> isymbol =
738 factory->InternalizeString(istring);
739 CHECK(isymbol->IsInternalizedString());
741 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
742 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
746 class RandomLengthResource : public v8::String::ExternalStringResource {
748 explicit RandomLengthResource(int length) : length_(length) {}
749 virtual const uint16_t* data() const { return string_; }
750 virtual size_t length() const { return length_; }
753 uint16_t string_[10];
758 class RandomLengthOneByteResource
759 : public v8::String::ExternalOneByteStringResource {
761 explicit RandomLengthOneByteResource(int length) : length_(length) {}
762 virtual const char* data() const { return string_; }
763 virtual size_t length() const { return length_; }
771 THREADED_TEST(NewExternalForVeryLongString) {
774 v8::HandleScope scope(env->GetIsolate());
775 v8::TryCatch try_catch;
776 RandomLengthOneByteResource r(1 << 30);
777 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
778 CHECK(str.IsEmpty());
779 CHECK(try_catch.HasCaught());
780 String::Utf8Value exception_value(try_catch.Exception());
781 CHECK_EQ("RangeError: Invalid string length", *exception_value);
786 v8::HandleScope scope(env->GetIsolate());
787 v8::TryCatch try_catch;
788 RandomLengthResource r(1 << 30);
789 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
790 CHECK(str.IsEmpty());
791 CHECK(try_catch.HasCaught());
792 String::Utf8Value exception_value(try_catch.Exception());
793 CHECK_EQ("RangeError: Invalid string length", *exception_value);
798 THREADED_TEST(ScavengeExternalString) {
799 i::FLAG_stress_compaction = false;
800 i::FLAG_gc_global = false;
801 int dispose_count = 0;
802 bool in_new_space = false;
804 v8::HandleScope scope(CcTest::isolate());
805 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
806 Local<String> string = String::NewExternal(
807 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
808 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
809 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
810 in_new_space = CcTest::heap()->InNewSpace(*istring);
811 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
812 CHECK_EQ(0, dispose_count);
814 CcTest::heap()->CollectGarbage(
815 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
816 CHECK_EQ(1, dispose_count);
820 THREADED_TEST(ScavengeExternalOneByteString) {
821 i::FLAG_stress_compaction = false;
822 i::FLAG_gc_global = false;
823 int dispose_count = 0;
824 bool in_new_space = false;
826 v8::HandleScope scope(CcTest::isolate());
827 const char* one_byte_string = "test string";
828 Local<String> string = String::NewExternal(
830 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
831 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
832 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
833 in_new_space = CcTest::heap()->InNewSpace(*istring);
834 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
835 CHECK_EQ(0, dispose_count);
837 CcTest::heap()->CollectGarbage(
838 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
839 CHECK_EQ(1, dispose_count);
843 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
845 // Only used by non-threaded tests, so it can use static fields.
846 static int dispose_calls;
847 static int dispose_count;
849 TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
850 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
854 if (dispose_) delete this;
861 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
862 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
865 TEST(ExternalStringWithDisposeHandling) {
866 const char* c_source = "1 + 2 * 3";
868 // Use a stack allocated external string resource allocated object.
869 TestOneByteResourceWithDisposeControl::dispose_count = 0;
870 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
871 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
874 v8::HandleScope scope(env->GetIsolate());
875 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
876 Local<Script> script = v8_compile(source);
877 Local<Value> value = script->Run();
878 CHECK(value->IsNumber());
879 CHECK_EQ(7, value->Int32Value());
880 CcTest::heap()->CollectAllAvailableGarbage();
881 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
883 CcTest::i_isolate()->compilation_cache()->Clear();
884 CcTest::heap()->CollectAllAvailableGarbage();
885 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
886 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
888 // Use a heap allocated external string resource allocated object.
889 TestOneByteResourceWithDisposeControl::dispose_count = 0;
890 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
891 TestOneByteResource* res_heap =
892 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
895 v8::HandleScope scope(env->GetIsolate());
896 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
897 Local<Script> script = v8_compile(source);
898 Local<Value> value = script->Run();
899 CHECK(value->IsNumber());
900 CHECK_EQ(7, value->Int32Value());
901 CcTest::heap()->CollectAllAvailableGarbage();
902 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
904 CcTest::i_isolate()->compilation_cache()->Clear();
905 CcTest::heap()->CollectAllAvailableGarbage();
906 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
907 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
911 THREADED_TEST(StringConcat) {
914 v8::HandleScope scope(env->GetIsolate());
915 const char* one_byte_string_1 = "function a_times_t";
916 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
917 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
918 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
919 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
920 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
921 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
922 Local<String> left = v8_str(one_byte_string_1);
924 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
925 Local<String> right =
926 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
927 i::DeleteArray(two_byte_source);
929 Local<String> source = String::Concat(left, right);
930 right = String::NewExternal(
932 new TestOneByteResource(i::StrDup(one_byte_extern_1)));
933 source = String::Concat(source, right);
934 right = String::NewExternal(
936 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
937 source = String::Concat(source, right);
938 right = v8_str(one_byte_string_2);
939 source = String::Concat(source, right);
941 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
942 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
943 i::DeleteArray(two_byte_source);
945 source = String::Concat(source, right);
946 right = String::NewExternal(
948 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
949 source = String::Concat(source, right);
950 Local<Script> script = v8_compile(source);
951 Local<Value> value = script->Run();
952 CHECK(value->IsNumber());
953 CHECK_EQ(68, value->Int32Value());
955 CcTest::i_isolate()->compilation_cache()->Clear();
956 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
957 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
961 THREADED_TEST(GlobalProperties) {
963 v8::HandleScope scope(env->GetIsolate());
964 v8::Handle<v8::Object> global = env->Global();
965 global->Set(v8_str("pi"), v8_num(3.1415926));
966 Local<Value> pi = global->Get(v8_str("pi"));
967 CHECK_EQ(3.1415926, pi->NumberValue());
972 static void CheckReturnValue(const T& t, i::Address callback) {
973 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
974 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
975 CHECK_EQ(CcTest::isolate(), t.GetIsolate());
976 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
977 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
979 bool is_runtime = (*o)->IsTheHole();
981 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
982 rv.Set(v8::Handle<v8::Object>());
983 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
984 CHECK_EQ(is_runtime, (*o)->IsTheHole());
986 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
987 // If CPU profiler is active check that when API callback is invoked
988 // VMState is set to EXTERNAL.
989 if (isolate->cpu_profiler()->is_profiling()) {
990 CHECK_EQ(v8::EXTERNAL, isolate->current_vm_state());
991 CHECK(isolate->external_callback_scope());
992 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
997 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
998 i::Address callback) {
999 ApiTestFuzzer::Fuzz();
1000 CheckReturnValue(info, callback);
1001 info.GetReturnValue().Set(v8_str("bad value"));
1002 info.GetReturnValue().Set(v8_num(102));
1006 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1007 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1011 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1012 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1015 static void construct_callback(
1016 const v8::FunctionCallbackInfo<Value>& info) {
1017 ApiTestFuzzer::Fuzz();
1018 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1019 info.This()->Set(v8_str("x"), v8_num(1));
1020 info.This()->Set(v8_str("y"), v8_num(2));
1021 info.GetReturnValue().Set(v8_str("bad value"));
1022 info.GetReturnValue().Set(info.This());
1026 static void Return239Callback(
1027 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1028 ApiTestFuzzer::Fuzz();
1029 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1030 info.GetReturnValue().Set(v8_str("bad value"));
1031 info.GetReturnValue().Set(v8_num(239));
1035 template<typename Handler>
1036 static void TestFunctionTemplateInitializer(Handler handler,
1037 Handler handler_2) {
1038 // Test constructor calls.
1041 v8::Isolate* isolate = env->GetIsolate();
1042 v8::HandleScope scope(isolate);
1044 Local<v8::FunctionTemplate> fun_templ =
1045 v8::FunctionTemplate::New(isolate, handler);
1046 Local<Function> fun = fun_templ->GetFunction();
1047 env->Global()->Set(v8_str("obj"), fun);
1048 Local<Script> script = v8_compile("obj()");
1049 for (int i = 0; i < 30; i++) {
1050 CHECK_EQ(102, script->Run()->Int32Value());
1053 // Use SetCallHandler to initialize a function template, should work like
1054 // the previous one.
1057 v8::Isolate* isolate = env->GetIsolate();
1058 v8::HandleScope scope(isolate);
1060 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1061 fun_templ->SetCallHandler(handler_2);
1062 Local<Function> fun = fun_templ->GetFunction();
1063 env->Global()->Set(v8_str("obj"), fun);
1064 Local<Script> script = v8_compile("obj()");
1065 for (int i = 0; i < 30; i++) {
1066 CHECK_EQ(102, script->Run()->Int32Value());
1072 template<typename Constructor, typename Accessor>
1073 static void TestFunctionTemplateAccessor(Constructor constructor,
1074 Accessor accessor) {
1076 v8::HandleScope scope(env->GetIsolate());
1078 Local<v8::FunctionTemplate> fun_templ =
1079 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1080 fun_templ->SetClassName(v8_str("funky"));
1081 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1082 Local<Function> fun = fun_templ->GetFunction();
1083 env->Global()->Set(v8_str("obj"), fun);
1084 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1085 CHECK_EQ(v8_str("[object funky]"), result);
1086 CompileRun("var obj_instance = new obj();");
1087 Local<Script> script;
1088 script = v8_compile("obj_instance.x");
1089 for (int i = 0; i < 30; i++) {
1090 CHECK_EQ(1, script->Run()->Int32Value());
1092 script = v8_compile("obj_instance.m");
1093 for (int i = 0; i < 30; i++) {
1094 CHECK_EQ(239, script->Run()->Int32Value());
1099 THREADED_PROFILED_TEST(FunctionTemplate) {
1100 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1101 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1105 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1106 ApiTestFuzzer::Fuzz();
1107 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1108 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1112 template<typename Callback>
1113 static void TestSimpleCallback(Callback callback) {
1115 v8::Isolate* isolate = env->GetIsolate();
1116 v8::HandleScope scope(isolate);
1118 v8::Handle<v8::ObjectTemplate> object_template =
1119 v8::ObjectTemplate::New(isolate);
1120 object_template->Set(isolate, "callback",
1121 v8::FunctionTemplate::New(isolate, callback));
1122 v8::Local<v8::Object> object = object_template->NewInstance();
1123 (*env)->Global()->Set(v8_str("callback_object"), object);
1124 v8::Handle<v8::Script> script;
1125 script = v8_compile("callback_object.callback(17)");
1126 for (int i = 0; i < 30; i++) {
1127 CHECK_EQ(51424, script->Run()->Int32Value());
1129 script = v8_compile("callback_object.callback(17, 24)");
1130 for (int i = 0; i < 30; i++) {
1131 CHECK_EQ(51425, script->Run()->Int32Value());
1136 THREADED_PROFILED_TEST(SimpleCallback) {
1137 TestSimpleCallback(SimpleCallback);
1141 template<typename T>
1142 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1144 // constant return values
1145 static int32_t fast_return_value_int32 = 471;
1146 static uint32_t fast_return_value_uint32 = 571;
1147 static const double kFastReturnValueDouble = 2.7;
1148 // variable return values
1149 static bool fast_return_value_bool = false;
1150 enum ReturnValueOddball {
1152 kUndefinedReturnValue,
1153 kEmptyStringReturnValue
1155 static ReturnValueOddball fast_return_value_void;
1156 static bool fast_return_value_object_is_empty = false;
1158 // Helper function to avoid compiler error: insufficient contextual information
1159 // to determine type when applying FUNCTION_ADDR to a template function.
1160 static i::Address address_of(v8::FunctionCallback callback) {
1161 return FUNCTION_ADDR(callback);
1165 void FastReturnValueCallback<int32_t>(
1166 const v8::FunctionCallbackInfo<v8::Value>& info) {
1167 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1168 info.GetReturnValue().Set(fast_return_value_int32);
1172 void FastReturnValueCallback<uint32_t>(
1173 const v8::FunctionCallbackInfo<v8::Value>& info) {
1174 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1175 info.GetReturnValue().Set(fast_return_value_uint32);
1179 void FastReturnValueCallback<double>(
1180 const v8::FunctionCallbackInfo<v8::Value>& info) {
1181 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1182 info.GetReturnValue().Set(kFastReturnValueDouble);
1186 void FastReturnValueCallback<bool>(
1187 const v8::FunctionCallbackInfo<v8::Value>& info) {
1188 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1189 info.GetReturnValue().Set(fast_return_value_bool);
1193 void FastReturnValueCallback<void>(
1194 const v8::FunctionCallbackInfo<v8::Value>& info) {
1195 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1196 switch (fast_return_value_void) {
1197 case kNullReturnValue:
1198 info.GetReturnValue().SetNull();
1200 case kUndefinedReturnValue:
1201 info.GetReturnValue().SetUndefined();
1203 case kEmptyStringReturnValue:
1204 info.GetReturnValue().SetEmptyString();
1210 void FastReturnValueCallback<Object>(
1211 const v8::FunctionCallbackInfo<v8::Value>& info) {
1212 v8::Handle<v8::Object> object;
1213 if (!fast_return_value_object_is_empty) {
1214 object = Object::New(info.GetIsolate());
1216 info.GetReturnValue().Set(object);
1219 template<typename T>
1220 Handle<Value> TestFastReturnValues() {
1222 v8::Isolate* isolate = env->GetIsolate();
1223 v8::EscapableHandleScope scope(isolate);
1224 v8::Handle<v8::ObjectTemplate> object_template =
1225 v8::ObjectTemplate::New(isolate);
1226 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1227 object_template->Set(isolate, "callback",
1228 v8::FunctionTemplate::New(isolate, callback));
1229 v8::Local<v8::Object> object = object_template->NewInstance();
1230 (*env)->Global()->Set(v8_str("callback_object"), object);
1231 return scope.Escape(CompileRun("callback_object.callback()"));
1235 THREADED_PROFILED_TEST(FastReturnValues) {
1237 v8::Isolate* isolate = env->GetIsolate();
1238 v8::HandleScope scope(isolate);
1239 v8::Handle<v8::Value> value;
1240 // check int32_t and uint32_t
1241 int32_t int_values[] = {
1243 i::Smi::kMinValue, i::Smi::kMaxValue
1245 for (size_t i = 0; i < arraysize(int_values); i++) {
1246 for (int modifier = -1; modifier <= 1; modifier++) {
1247 int int_value = int_values[i] + modifier;
1249 fast_return_value_int32 = int_value;
1250 value = TestFastReturnValues<int32_t>();
1251 CHECK(value->IsInt32());
1252 CHECK(fast_return_value_int32 == value->Int32Value());
1254 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1255 value = TestFastReturnValues<uint32_t>();
1256 CHECK(value->IsUint32());
1257 CHECK(fast_return_value_uint32 == value->Uint32Value());
1261 value = TestFastReturnValues<double>();
1262 CHECK(value->IsNumber());
1263 CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
1264 // check bool values
1265 for (int i = 0; i < 2; i++) {
1266 fast_return_value_bool = i == 0;
1267 value = TestFastReturnValues<bool>();
1268 CHECK(value->IsBoolean());
1269 CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
1272 ReturnValueOddball oddballs[] = {
1274 kUndefinedReturnValue,
1275 kEmptyStringReturnValue
1277 for (size_t i = 0; i < arraysize(oddballs); i++) {
1278 fast_return_value_void = oddballs[i];
1279 value = TestFastReturnValues<void>();
1280 switch (fast_return_value_void) {
1281 case kNullReturnValue:
1282 CHECK(value->IsNull());
1284 case kUndefinedReturnValue:
1285 CHECK(value->IsUndefined());
1287 case kEmptyStringReturnValue:
1288 CHECK(value->IsString());
1289 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1294 fast_return_value_object_is_empty = false;
1295 value = TestFastReturnValues<Object>();
1296 CHECK(value->IsObject());
1297 fast_return_value_object_is_empty = true;
1298 value = TestFastReturnValues<Object>();
1299 CHECK(value->IsUndefined());
1303 THREADED_TEST(FunctionTemplateSetLength) {
1305 v8::Isolate* isolate = env->GetIsolate();
1306 v8::HandleScope scope(isolate);
1308 Local<v8::FunctionTemplate> fun_templ =
1309 v8::FunctionTemplate::New(isolate,
1311 Handle<v8::Value>(),
1312 Handle<v8::Signature>(),
1314 Local<Function> fun = fun_templ->GetFunction();
1315 env->Global()->Set(v8_str("obj"), fun);
1316 Local<Script> script = v8_compile("obj.length");
1317 CHECK_EQ(23, script->Run()->Int32Value());
1320 Local<v8::FunctionTemplate> fun_templ =
1321 v8::FunctionTemplate::New(isolate, handle_callback);
1322 fun_templ->SetLength(22);
1323 Local<Function> fun = fun_templ->GetFunction();
1324 env->Global()->Set(v8_str("obj"), fun);
1325 Local<Script> script = v8_compile("obj.length");
1326 CHECK_EQ(22, script->Run()->Int32Value());
1329 // Without setting length it defaults to 0.
1330 Local<v8::FunctionTemplate> fun_templ =
1331 v8::FunctionTemplate::New(isolate, handle_callback);
1332 Local<Function> fun = fun_templ->GetFunction();
1333 env->Global()->Set(v8_str("obj"), fun);
1334 Local<Script> script = v8_compile("obj.length");
1335 CHECK_EQ(0, script->Run()->Int32Value());
1340 static void* expected_ptr;
1341 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1342 void* ptr = v8::External::Cast(*args.Data())->Value();
1343 CHECK_EQ(expected_ptr, ptr);
1344 args.GetReturnValue().Set(true);
1348 static void TestExternalPointerWrapping() {
1350 v8::Isolate* isolate = env->GetIsolate();
1351 v8::HandleScope scope(isolate);
1353 v8::Handle<v8::Value> data =
1354 v8::External::New(isolate, expected_ptr);
1356 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1357 obj->Set(v8_str("func"),
1358 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1359 env->Global()->Set(v8_str("obj"), obj);
1362 "function foo() {\n"
1363 " for (var i = 0; i < 13; i++) obj.func();\n"
1365 "foo(), true")->BooleanValue());
1369 THREADED_TEST(ExternalWrap) {
1370 // Check heap allocated object.
1373 TestExternalPointerWrapping();
1376 // Check stack allocated object.
1378 expected_ptr = &foo;
1379 TestExternalPointerWrapping();
1381 // Check not aligned addresses.
1383 char* s = new char[n];
1384 for (int i = 0; i < n; i++) {
1385 expected_ptr = s + i;
1386 TestExternalPointerWrapping();
1391 // Check several invalid addresses.
1392 expected_ptr = reinterpret_cast<void*>(1);
1393 TestExternalPointerWrapping();
1395 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1396 TestExternalPointerWrapping();
1398 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1399 TestExternalPointerWrapping();
1401 #if defined(V8_HOST_ARCH_X64)
1402 // Check a value with a leading 1 bit in x64 Smi encoding.
1403 expected_ptr = reinterpret_cast<void*>(0x400000000);
1404 TestExternalPointerWrapping();
1406 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1407 TestExternalPointerWrapping();
1409 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1410 TestExternalPointerWrapping();
1415 THREADED_TEST(FindInstanceInPrototypeChain) {
1417 v8::Isolate* isolate = env->GetIsolate();
1418 v8::HandleScope scope(isolate);
1420 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1421 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1422 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1423 derived->Inherit(base);
1425 Local<v8::Function> base_function = base->GetFunction();
1426 Local<v8::Function> derived_function = derived->GetFunction();
1427 Local<v8::Function> other_function = other->GetFunction();
1429 Local<v8::Object> base_instance = base_function->NewInstance();
1430 Local<v8::Object> derived_instance = derived_function->NewInstance();
1431 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1432 Local<v8::Object> other_instance = other_function->NewInstance();
1433 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1434 other_instance->Set(v8_str("__proto__"), derived_instance2);
1436 // base_instance is only an instance of base.
1437 CHECK_EQ(base_instance,
1438 base_instance->FindInstanceInPrototypeChain(base));
1439 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1440 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1442 // derived_instance is an instance of base and derived.
1443 CHECK_EQ(derived_instance,
1444 derived_instance->FindInstanceInPrototypeChain(base));
1445 CHECK_EQ(derived_instance,
1446 derived_instance->FindInstanceInPrototypeChain(derived));
1447 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1449 // other_instance is an instance of other and its immediate
1450 // prototype derived_instance2 is an instance of base and derived.
1451 // Note, derived_instance is an instance of base and derived too,
1452 // but it comes after derived_instance2 in the prototype chain of
1454 CHECK_EQ(derived_instance2,
1455 other_instance->FindInstanceInPrototypeChain(base));
1456 CHECK_EQ(derived_instance2,
1457 other_instance->FindInstanceInPrototypeChain(derived));
1458 CHECK_EQ(other_instance,
1459 other_instance->FindInstanceInPrototypeChain(other));
1463 THREADED_TEST(TinyInteger) {
1465 v8::Isolate* isolate = env->GetIsolate();
1466 v8::HandleScope scope(isolate);
1468 int32_t value = 239;
1469 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1470 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1472 value_obj = v8::Integer::New(isolate, value);
1473 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1477 THREADED_TEST(BigSmiInteger) {
1479 v8::HandleScope scope(env->GetIsolate());
1480 v8::Isolate* isolate = CcTest::isolate();
1482 int32_t value = i::Smi::kMaxValue;
1483 // We cannot add one to a Smi::kMaxValue without wrapping.
1484 if (i::SmiValuesAre31Bits()) {
1485 CHECK(i::Smi::IsValid(value));
1486 CHECK(!i::Smi::IsValid(value + 1));
1488 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1489 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1491 value_obj = v8::Integer::New(isolate, value);
1492 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1497 THREADED_TEST(BigInteger) {
1499 v8::HandleScope scope(env->GetIsolate());
1500 v8::Isolate* isolate = CcTest::isolate();
1502 // We cannot add one to a Smi::kMaxValue without wrapping.
1503 if (i::SmiValuesAre31Bits()) {
1504 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1505 // The code will not be run in that case, due to the "if" guard.
1507 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1508 CHECK(value > i::Smi::kMaxValue);
1509 CHECK(!i::Smi::IsValid(value));
1511 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1512 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1514 value_obj = v8::Integer::New(isolate, value);
1515 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1520 THREADED_TEST(TinyUnsignedInteger) {
1522 v8::HandleScope scope(env->GetIsolate());
1523 v8::Isolate* isolate = CcTest::isolate();
1525 uint32_t value = 239;
1527 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1528 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1530 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1531 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1535 THREADED_TEST(BigUnsignedSmiInteger) {
1537 v8::HandleScope scope(env->GetIsolate());
1538 v8::Isolate* isolate = CcTest::isolate();
1540 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1541 CHECK(i::Smi::IsValid(value));
1542 CHECK(!i::Smi::IsValid(value + 1));
1544 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1545 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1547 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1548 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1552 THREADED_TEST(BigUnsignedInteger) {
1554 v8::HandleScope scope(env->GetIsolate());
1555 v8::Isolate* isolate = CcTest::isolate();
1557 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1558 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1559 CHECK(!i::Smi::IsValid(value));
1561 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1562 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1564 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1565 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1569 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1571 v8::HandleScope scope(env->GetIsolate());
1572 v8::Isolate* isolate = CcTest::isolate();
1574 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1575 uint32_t value = INT32_MAX_AS_UINT + 1;
1576 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1578 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1579 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1581 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1582 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1586 THREADED_TEST(IsNativeError) {
1588 v8::HandleScope scope(env->GetIsolate());
1589 v8::Handle<Value> syntax_error = CompileRun(
1590 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1591 CHECK(syntax_error->IsNativeError());
1592 v8::Handle<Value> not_error = CompileRun("{a:42}");
1593 CHECK(!not_error->IsNativeError());
1594 v8::Handle<Value> not_object = CompileRun("42");
1595 CHECK(!not_object->IsNativeError());
1599 THREADED_TEST(IsGeneratorFunctionOrObject) {
1601 v8::HandleScope scope(env->GetIsolate());
1603 CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1604 v8::Handle<Value> gen = CompileRun("gen");
1605 v8::Handle<Value> genObj = CompileRun("gen()");
1606 v8::Handle<Value> object = CompileRun("{a:42}");
1607 v8::Handle<Value> func = CompileRun("func");
1609 CHECK(gen->IsGeneratorFunction());
1610 CHECK(gen->IsFunction());
1611 CHECK(!gen->IsGeneratorObject());
1613 CHECK(!genObj->IsGeneratorFunction());
1614 CHECK(!genObj->IsFunction());
1615 CHECK(genObj->IsGeneratorObject());
1617 CHECK(!object->IsGeneratorFunction());
1618 CHECK(!object->IsFunction());
1619 CHECK(!object->IsGeneratorObject());
1621 CHECK(!func->IsGeneratorFunction());
1622 CHECK(func->IsFunction());
1623 CHECK(!func->IsGeneratorObject());
1627 THREADED_TEST(ArgumentsObject) {
1629 v8::HandleScope scope(env->GetIsolate());
1630 v8::Handle<Value> arguments_object =
1631 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1632 CHECK(arguments_object->IsArgumentsObject());
1633 v8::Handle<Value> array = CompileRun("[1,2,3]");
1634 CHECK(!array->IsArgumentsObject());
1635 v8::Handle<Value> object = CompileRun("{a:42}");
1636 CHECK(!object->IsArgumentsObject());
1640 THREADED_TEST(IsMapOrSet) {
1642 v8::HandleScope scope(env->GetIsolate());
1643 v8::Handle<Value> map = CompileRun("new Map()");
1644 v8::Handle<Value> set = CompileRun("new Set()");
1645 v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1646 v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1647 CHECK(map->IsMap());
1648 CHECK(set->IsSet());
1649 CHECK(weak_map->IsWeakMap());
1650 CHECK(weak_set->IsWeakSet());
1652 CHECK(!map->IsSet());
1653 CHECK(!map->IsWeakMap());
1654 CHECK(!map->IsWeakSet());
1656 CHECK(!set->IsMap());
1657 CHECK(!set->IsWeakMap());
1658 CHECK(!set->IsWeakSet());
1660 CHECK(!weak_map->IsMap());
1661 CHECK(!weak_map->IsSet());
1662 CHECK(!weak_map->IsWeakSet());
1664 CHECK(!weak_set->IsMap());
1665 CHECK(!weak_set->IsSet());
1666 CHECK(!weak_set->IsWeakMap());
1668 v8::Handle<Value> object = CompileRun("{a:42}");
1669 CHECK(!object->IsMap());
1670 CHECK(!object->IsSet());
1671 CHECK(!object->IsWeakMap());
1672 CHECK(!object->IsWeakSet());
1676 THREADED_TEST(StringObject) {
1678 v8::HandleScope scope(env->GetIsolate());
1679 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1680 CHECK(boxed_string->IsStringObject());
1681 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1682 CHECK(!unboxed_string->IsStringObject());
1683 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1684 CHECK(!boxed_not_string->IsStringObject());
1685 v8::Handle<Value> not_object = CompileRun("0");
1686 CHECK(!not_object->IsStringObject());
1687 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1688 CHECK(!as_boxed.IsEmpty());
1689 Local<v8::String> the_string = as_boxed->ValueOf();
1690 CHECK(!the_string.IsEmpty());
1691 ExpectObject("\"test\"", the_string);
1692 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1693 CHECK(new_boxed_string->IsStringObject());
1694 as_boxed = new_boxed_string.As<v8::StringObject>();
1695 the_string = as_boxed->ValueOf();
1696 CHECK(!the_string.IsEmpty());
1697 ExpectObject("\"test\"", the_string);
1701 THREADED_TEST(NumberObject) {
1703 v8::HandleScope scope(env->GetIsolate());
1704 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1705 CHECK(boxed_number->IsNumberObject());
1706 v8::Handle<Value> unboxed_number = CompileRun("42");
1707 CHECK(!unboxed_number->IsNumberObject());
1708 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1709 CHECK(!boxed_not_number->IsNumberObject());
1710 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1711 CHECK(!as_boxed.IsEmpty());
1712 double the_number = as_boxed->ValueOf();
1713 CHECK_EQ(42.0, the_number);
1714 v8::Handle<v8::Value> new_boxed_number =
1715 v8::NumberObject::New(env->GetIsolate(), 43);
1716 CHECK(new_boxed_number->IsNumberObject());
1717 as_boxed = new_boxed_number.As<v8::NumberObject>();
1718 the_number = as_boxed->ValueOf();
1719 CHECK_EQ(43.0, the_number);
1723 THREADED_TEST(BooleanObject) {
1725 v8::HandleScope scope(env->GetIsolate());
1726 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1727 CHECK(boxed_boolean->IsBooleanObject());
1728 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1729 CHECK(!unboxed_boolean->IsBooleanObject());
1730 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1731 CHECK(!boxed_not_boolean->IsBooleanObject());
1732 v8::Handle<v8::BooleanObject> as_boxed =
1733 boxed_boolean.As<v8::BooleanObject>();
1734 CHECK(!as_boxed.IsEmpty());
1735 bool the_boolean = as_boxed->ValueOf();
1736 CHECK_EQ(true, the_boolean);
1737 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1738 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1739 CHECK(boxed_true->IsBooleanObject());
1740 CHECK(boxed_false->IsBooleanObject());
1741 as_boxed = boxed_true.As<v8::BooleanObject>();
1742 CHECK_EQ(true, as_boxed->ValueOf());
1743 as_boxed = boxed_false.As<v8::BooleanObject>();
1744 CHECK_EQ(false, as_boxed->ValueOf());
1748 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1750 v8::HandleScope scope(env->GetIsolate());
1752 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1753 CHECK(primitive_false->IsBoolean());
1754 CHECK(!primitive_false->IsBooleanObject());
1755 CHECK(!primitive_false->BooleanValue());
1756 CHECK(!primitive_false->IsTrue());
1757 CHECK(primitive_false->IsFalse());
1759 Local<Value> false_value = BooleanObject::New(false);
1760 CHECK(!false_value->IsBoolean());
1761 CHECK(false_value->IsBooleanObject());
1762 CHECK(false_value->BooleanValue());
1763 CHECK(!false_value->IsTrue());
1764 CHECK(!false_value->IsFalse());
1766 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1767 CHECK(!false_boolean_object->IsBoolean());
1768 CHECK(false_boolean_object->IsBooleanObject());
1769 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1770 // CHECK(false_boolean_object->BooleanValue());
1771 CHECK(!false_boolean_object->ValueOf());
1772 CHECK(!false_boolean_object->IsTrue());
1773 CHECK(!false_boolean_object->IsFalse());
1775 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1776 CHECK(primitive_true->IsBoolean());
1777 CHECK(!primitive_true->IsBooleanObject());
1778 CHECK(primitive_true->BooleanValue());
1779 CHECK(primitive_true->IsTrue());
1780 CHECK(!primitive_true->IsFalse());
1782 Local<Value> true_value = BooleanObject::New(true);
1783 CHECK(!true_value->IsBoolean());
1784 CHECK(true_value->IsBooleanObject());
1785 CHECK(true_value->BooleanValue());
1786 CHECK(!true_value->IsTrue());
1787 CHECK(!true_value->IsFalse());
1789 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1790 CHECK(!true_boolean_object->IsBoolean());
1791 CHECK(true_boolean_object->IsBooleanObject());
1792 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1793 // CHECK(true_boolean_object->BooleanValue());
1794 CHECK(true_boolean_object->ValueOf());
1795 CHECK(!true_boolean_object->IsTrue());
1796 CHECK(!true_boolean_object->IsFalse());
1800 THREADED_TEST(Number) {
1802 v8::HandleScope scope(env->GetIsolate());
1803 double PI = 3.1415926;
1804 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1805 CHECK_EQ(PI, pi_obj->NumberValue());
1809 THREADED_TEST(ToNumber) {
1811 v8::Isolate* isolate = CcTest::isolate();
1812 v8::HandleScope scope(isolate);
1813 Local<String> str = v8_str("3.1415926");
1814 CHECK_EQ(3.1415926, str->NumberValue());
1815 v8::Handle<v8::Boolean> t = v8::True(isolate);
1816 CHECK_EQ(1.0, t->NumberValue());
1817 v8::Handle<v8::Boolean> f = v8::False(isolate);
1818 CHECK_EQ(0.0, f->NumberValue());
1822 THREADED_TEST(Date) {
1824 v8::HandleScope scope(env->GetIsolate());
1825 double PI = 3.1415926;
1826 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1827 CHECK_EQ(3.0, date->NumberValue());
1828 date.As<v8::Date>()->Set(v8_str("property"),
1829 v8::Integer::New(env->GetIsolate(), 42));
1830 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1834 THREADED_TEST(Boolean) {
1836 v8::Isolate* isolate = env->GetIsolate();
1837 v8::HandleScope scope(isolate);
1838 v8::Handle<v8::Boolean> t = v8::True(isolate);
1840 v8::Handle<v8::Boolean> f = v8::False(isolate);
1842 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1843 CHECK(!u->BooleanValue());
1844 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1845 CHECK(!n->BooleanValue());
1846 v8::Handle<String> str1 = v8_str("");
1847 CHECK(!str1->BooleanValue());
1848 v8::Handle<String> str2 = v8_str("x");
1849 CHECK(str2->BooleanValue());
1850 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1851 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1852 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1853 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1854 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1858 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1859 ApiTestFuzzer::Fuzz();
1860 args.GetReturnValue().Set(v8_num(13.4));
1864 static void GetM(Local<String> name,
1865 const v8::PropertyCallbackInfo<v8::Value>& info) {
1866 ApiTestFuzzer::Fuzz();
1867 info.GetReturnValue().Set(v8_num(876));
1871 THREADED_TEST(GlobalPrototype) {
1872 v8::Isolate* isolate = CcTest::isolate();
1873 v8::HandleScope scope(isolate);
1874 v8::Handle<v8::FunctionTemplate> func_templ =
1875 v8::FunctionTemplate::New(isolate);
1876 func_templ->PrototypeTemplate()->Set(
1877 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1878 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1879 templ->Set(isolate, "x", v8_num(200));
1880 templ->SetAccessor(v8_str("m"), GetM);
1881 LocalContext env(0, templ);
1882 v8::Handle<Script> script(v8_compile("dummy()"));
1883 v8::Handle<Value> result(script->Run());
1884 CHECK_EQ(13.4, result->NumberValue());
1885 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1886 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1890 THREADED_TEST(ObjectTemplate) {
1891 v8::Isolate* isolate = CcTest::isolate();
1892 v8::HandleScope scope(isolate);
1893 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1894 templ1->Set(isolate, "x", v8_num(10));
1895 templ1->Set(isolate, "y", v8_num(13));
1897 Local<v8::Object> instance1 = templ1->NewInstance();
1898 env->Global()->Set(v8_str("p"), instance1);
1899 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1900 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1901 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1902 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1903 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1904 templ2->Set(isolate, "a", v8_num(12));
1905 templ2->Set(isolate, "b", templ1);
1906 Local<v8::Object> instance2 = templ2->NewInstance();
1907 env->Global()->Set(v8_str("q"), instance2);
1908 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1909 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1910 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1911 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1915 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1916 ApiTestFuzzer::Fuzz();
1917 args.GetReturnValue().Set(v8_num(17.2));
1921 static void GetKnurd(Local<String> property,
1922 const v8::PropertyCallbackInfo<v8::Value>& info) {
1923 ApiTestFuzzer::Fuzz();
1924 info.GetReturnValue().Set(v8_num(15.2));
1928 THREADED_TEST(DescriptorInheritance) {
1929 v8::Isolate* isolate = CcTest::isolate();
1930 v8::HandleScope scope(isolate);
1931 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1932 super->PrototypeTemplate()->Set(isolate, "flabby",
1933 v8::FunctionTemplate::New(isolate,
1935 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1937 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1939 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1940 base1->Inherit(super);
1941 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1943 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1944 base2->Inherit(super);
1945 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1949 env->Global()->Set(v8_str("s"), super->GetFunction());
1950 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1951 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1953 // Checks right __proto__ chain.
1954 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1955 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1957 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1959 // Instance accessor should not be visible on function object or its prototype
1960 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1961 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1962 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1964 env->Global()->Set(v8_str("obj"),
1965 base1->GetFunction()->NewInstance());
1966 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1967 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1968 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1969 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1970 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1972 env->Global()->Set(v8_str("obj2"),
1973 base2->GetFunction()->NewInstance());
1974 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1975 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1976 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1977 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1978 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1980 // base1 and base2 cannot cross reference to each's prototype
1981 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1982 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1986 int echo_named_call_count;
1989 static void EchoNamedProperty(Local<Name> name,
1990 const v8::PropertyCallbackInfo<v8::Value>& info) {
1991 ApiTestFuzzer::Fuzz();
1992 CHECK_EQ(v8_str("data"), info.Data());
1993 echo_named_call_count++;
1994 info.GetReturnValue().Set(name);
1998 // Helper functions for Interceptor/Accessor interaction tests
2000 void SimpleAccessorGetter(Local<String> name,
2001 const v8::PropertyCallbackInfo<v8::Value>& info) {
2002 Handle<Object> self = Handle<Object>::Cast(info.This());
2003 info.GetReturnValue().Set(
2004 self->Get(String::Concat(v8_str("accessor_"), name)));
2007 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2008 const v8::PropertyCallbackInfo<void>& info) {
2009 Handle<Object> self = Handle<Object>::Cast(info.This());
2010 self->Set(String::Concat(v8_str("accessor_"), name), value);
2013 void SymbolAccessorGetter(Local<Name> name,
2014 const v8::PropertyCallbackInfo<v8::Value>& info) {
2015 CHECK(name->IsSymbol());
2016 Local<Symbol> sym = Local<Symbol>::Cast(name);
2017 if (sym->Name()->IsUndefined())
2019 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2022 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2023 const v8::PropertyCallbackInfo<void>& info) {
2024 CHECK(name->IsSymbol());
2025 Local<Symbol> sym = Local<Symbol>::Cast(name);
2026 if (sym->Name()->IsUndefined())
2028 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2031 void SymbolAccessorGetterReturnsDefault(
2032 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2033 CHECK(name->IsSymbol());
2034 Local<Symbol> sym = Local<Symbol>::Cast(name);
2035 if (sym->Name()->IsUndefined()) return;
2036 info.GetReturnValue().Set(info.Data());
2039 static void ThrowingSymbolAccessorGetter(
2040 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2041 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
2045 void EmptyInterceptorGetter(Local<Name> name,
2046 const v8::PropertyCallbackInfo<v8::Value>& info) {}
2049 void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
2050 const v8::PropertyCallbackInfo<v8::Value>& info) {}
2053 void EmptyGenericInterceptorGetter(
2054 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
2057 void EmptyGenericInterceptorSetter(
2058 Local<Name> name, Local<Value> value,
2059 const v8::PropertyCallbackInfo<v8::Value>& info) {}
2062 void StringInterceptorGetter(
2064 const v8::PropertyCallbackInfo<v8::Value>&
2065 info) { // Intercept names that start with 'interceptor_'.
2066 String::Utf8Value utf8(name);
2067 char* name_str = *utf8;
2068 char prefix[] = "interceptor_";
2070 for (i = 0; name_str[i] && prefix[i]; ++i) {
2071 if (name_str[i] != prefix[i]) return;
2073 Handle<Object> self = Handle<Object>::Cast(info.This());
2074 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
2078 void StringInterceptorSetter(Local<String> name, Local<Value> value,
2079 const v8::PropertyCallbackInfo<v8::Value>& info) {
2080 // Intercept accesses that set certain integer values, for which the name does
2081 // not start with 'accessor_'.
2082 String::Utf8Value utf8(name);
2083 char* name_str = *utf8;
2084 char prefix[] = "accessor_";
2086 for (i = 0; name_str[i] && prefix[i]; ++i) {
2087 if (name_str[i] != prefix[i]) break;
2089 if (!prefix[i]) return;
2091 if (value->IsInt32() && value->Int32Value() < 10000) {
2092 Handle<Object> self = Handle<Object>::Cast(info.This());
2093 self->SetHiddenValue(name, value);
2094 info.GetReturnValue().Set(value);
2098 void InterceptorGetter(Local<Name> generic_name,
2099 const v8::PropertyCallbackInfo<v8::Value>& info) {
2100 if (generic_name->IsSymbol()) return;
2101 StringInterceptorGetter(Local<String>::Cast(generic_name), info);
2104 void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
2105 const v8::PropertyCallbackInfo<v8::Value>& info) {
2106 if (generic_name->IsSymbol()) return;
2107 StringInterceptorSetter(Local<String>::Cast(generic_name), value, info);
2110 void GenericInterceptorGetter(Local<Name> generic_name,
2111 const v8::PropertyCallbackInfo<v8::Value>& info) {
2113 if (generic_name->IsSymbol()) {
2114 Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
2115 if (name->IsUndefined()) return;
2116 str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
2118 Local<String> name = Local<String>::Cast(generic_name);
2119 String::Utf8Value utf8(name);
2120 char* name_str = *utf8;
2121 if (*name_str == '_') return;
2122 str = String::Concat(v8_str("_str_"), name);
2125 Handle<Object> self = Handle<Object>::Cast(info.This());
2126 info.GetReturnValue().Set(self->Get(str));
2129 void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
2130 const v8::PropertyCallbackInfo<v8::Value>& info) {
2132 if (generic_name->IsSymbol()) {
2133 Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
2134 if (name->IsUndefined()) return;
2135 str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
2137 Local<String> name = Local<String>::Cast(generic_name);
2138 String::Utf8Value utf8(name);
2139 char* name_str = *utf8;
2140 if (*name_str == '_') return;
2141 str = String::Concat(v8_str("_str_"), name);
2144 Handle<Object> self = Handle<Object>::Cast(info.This());
2145 self->Set(str, value);
2146 info.GetReturnValue().Set(value);
2149 void AddAccessor(Handle<FunctionTemplate> templ,
2150 Handle<String> name,
2151 v8::AccessorGetterCallback getter,
2152 v8::AccessorSetterCallback setter) {
2153 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2156 void AddInterceptor(Handle<FunctionTemplate> templ,
2157 v8::NamedPropertyGetterCallback getter,
2158 v8::NamedPropertySetterCallback setter) {
2159 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
2163 void AddAccessor(Handle<FunctionTemplate> templ,
2165 v8::AccessorNameGetterCallback getter,
2166 v8::AccessorNameSetterCallback setter) {
2167 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2170 void AddInterceptor(Handle<FunctionTemplate> templ,
2171 v8::GenericNamedPropertyGetterCallback getter,
2172 v8::GenericNamedPropertySetterCallback setter) {
2173 templ->InstanceTemplate()->SetHandler(
2174 v8::NamedPropertyHandlerConfiguration(getter, setter));
2178 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
2179 v8::HandleScope scope(CcTest::isolate());
2180 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2181 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2182 child->Inherit(parent);
2183 AddAccessor(parent, v8_str("age"),
2184 SimpleAccessorGetter, SimpleAccessorSetter);
2185 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2187 env->Global()->Set(v8_str("Child"), child->GetFunction());
2188 CompileRun("var child = new Child;"
2190 ExpectBoolean("child.hasOwnProperty('age')", false);
2191 ExpectInt32("child.age", 10);
2192 ExpectInt32("child.accessor_age", 10);
2196 THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
2198 v8::Isolate* isolate = CcTest::isolate();
2199 v8::HandleScope scope(isolate);
2200 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2201 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2202 v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
2204 child->Inherit(parent);
2205 AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
2206 AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
2208 env->Global()->Set(v8_str("Child"), child->GetFunction());
2209 env->Global()->Set(v8_str("age"), age);
2211 "var child = new Child;"
2212 "child[age] = 10;");
2213 ExpectInt32("child[age]", 10);
2214 ExpectBoolean("child.hasOwnProperty('age')", false);
2215 ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
2219 THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
2221 v8::Isolate* isolate = CcTest::isolate();
2222 v8::HandleScope scope(isolate);
2223 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2224 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2225 v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
2226 v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
2228 child->Inherit(parent);
2229 AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
2230 AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
2232 env->Global()->Set(v8_str("Child"), child->GetFunction());
2233 env->Global()->Set(v8_str("age"), age);
2234 env->Global()->Set(v8_str("anon"), anon);
2236 "var child = new Child;"
2237 "child[age] = 10;");
2238 ExpectInt32("child[age]", 10);
2239 ExpectInt32("child._sym_age", 10);
2241 // Check that it also sees strings.
2242 CompileRun("child.foo = 47");
2243 ExpectInt32("child.foo", 47);
2244 ExpectInt32("child._str_foo", 47);
2246 // Check that the interceptor can punt (in this case, on anonymous symbols).
2247 CompileRun("child[anon] = 31337");
2248 ExpectInt32("child[anon]", 31337);
2252 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
2253 v8::Isolate* isolate = CcTest::isolate();
2254 v8::HandleScope scope(isolate);
2256 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2257 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2258 CHECK(a->map()->instance_descriptors()->IsFixedArray());
2259 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2260 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2261 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2262 // But we should still have an ExecutableAccessorInfo.
2263 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2264 i::LookupResult lookup(i_isolate);
2265 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2266 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2267 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2268 CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
2272 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2273 v8::HandleScope scope(CcTest::isolate());
2274 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2275 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2277 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2278 CompileRun("var o1 = new Constructor;"
2279 "o1.a = 1;" // Ensure a and x share the descriptor array.
2280 "Object.defineProperty(o1, 'x', {value: 10});");
2281 CompileRun("var o2 = new Constructor;"
2283 "Object.defineProperty(o2, 'x', {value: 10});");
2287 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2288 v8::Isolate* isolate = CcTest::isolate();
2289 v8::HandleScope scope(isolate);
2290 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2291 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2292 child->Inherit(parent);
2293 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2295 env->Global()->Set(v8_str("Child"), child->GetFunction());
2296 CompileRun("var child = new Child;"
2297 "var parent = child.__proto__;"
2298 "Object.defineProperty(parent, 'age', "
2299 " {get: function(){ return this.accessor_age; }, "
2300 " set: function(v){ this.accessor_age = v; }, "
2301 " enumerable: true, configurable: true});"
2303 ExpectBoolean("child.hasOwnProperty('age')", false);
2304 ExpectInt32("child.age", 10);
2305 ExpectInt32("child.accessor_age", 10);
2309 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2310 v8::Isolate* isolate = CcTest::isolate();
2311 v8::HandleScope scope(isolate);
2312 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2313 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2314 child->Inherit(parent);
2315 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2317 env->Global()->Set(v8_str("Child"), child->GetFunction());
2318 CompileRun("var child = new Child;"
2319 "var parent = child.__proto__;"
2320 "parent.name = 'Alice';");
2321 ExpectBoolean("child.hasOwnProperty('name')", false);
2322 ExpectString("child.name", "Alice");
2323 CompileRun("child.name = 'Bob';");
2324 ExpectString("child.name", "Bob");
2325 ExpectBoolean("child.hasOwnProperty('name')", true);
2326 ExpectString("parent.name", "Alice");
2330 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2331 v8::HandleScope scope(CcTest::isolate());
2332 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2333 AddAccessor(templ, v8_str("age"),
2334 SimpleAccessorGetter, SimpleAccessorSetter);
2335 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2337 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2338 CompileRun("var obj = new Obj;"
2339 "function setAge(i){ obj.age = i; };"
2340 "for(var i = 0; i <= 10000; i++) setAge(i);");
2341 // All i < 10000 go to the interceptor.
2342 ExpectInt32("obj.interceptor_age", 9999);
2343 // The last i goes to the accessor.
2344 ExpectInt32("obj.accessor_age", 10000);
2348 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2349 v8::HandleScope scope(CcTest::isolate());
2350 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2351 AddAccessor(templ, v8_str("age"),
2352 SimpleAccessorGetter, SimpleAccessorSetter);
2353 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2355 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2356 CompileRun("var obj = new Obj;"
2357 "function setAge(i){ obj.age = i; };"
2358 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2359 // All i >= 10000 go to the accessor.
2360 ExpectInt32("obj.accessor_age", 10000);
2361 // The last i goes to the interceptor.
2362 ExpectInt32("obj.interceptor_age", 9999);
2366 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2367 v8::HandleScope scope(CcTest::isolate());
2368 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2369 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2370 child->Inherit(parent);
2371 AddAccessor(parent, v8_str("age"),
2372 SimpleAccessorGetter, SimpleAccessorSetter);
2373 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2375 env->Global()->Set(v8_str("Child"), child->GetFunction());
2376 CompileRun("var child = new Child;"
2377 "function setAge(i){ child.age = i; };"
2378 "for(var i = 0; i <= 10000; i++) setAge(i);");
2379 // All i < 10000 go to the interceptor.
2380 ExpectInt32("child.interceptor_age", 9999);
2381 // The last i goes to the accessor.
2382 ExpectInt32("child.accessor_age", 10000);
2386 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2387 v8::HandleScope scope(CcTest::isolate());
2388 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2389 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2390 child->Inherit(parent);
2391 AddAccessor(parent, v8_str("age"),
2392 SimpleAccessorGetter, SimpleAccessorSetter);
2393 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2395 env->Global()->Set(v8_str("Child"), child->GetFunction());
2396 CompileRun("var child = new Child;"
2397 "function setAge(i){ child.age = i; };"
2398 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2399 // All i >= 10000 go to the accessor.
2400 ExpectInt32("child.accessor_age", 10000);
2401 // The last i goes to the interceptor.
2402 ExpectInt32("child.interceptor_age", 9999);
2406 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2407 v8::HandleScope scope(CcTest::isolate());
2408 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2409 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2411 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2412 CompileRun("var obj = new Obj;"
2413 "function setter(i) { this.accessor_age = i; };"
2414 "function getter() { return this.accessor_age; };"
2415 "function setAge(i) { obj.age = i; };"
2416 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2417 "for(var i = 0; i <= 10000; i++) setAge(i);");
2418 // All i < 10000 go to the interceptor.
2419 ExpectInt32("obj.interceptor_age", 9999);
2420 // The last i goes to the JavaScript accessor.
2421 ExpectInt32("obj.accessor_age", 10000);
2422 // The installed JavaScript getter is still intact.
2423 // This last part is a regression test for issue 1651 and relies on the fact
2424 // that both interceptor and accessor are being installed on the same object.
2425 ExpectInt32("obj.age", 10000);
2426 ExpectBoolean("obj.hasOwnProperty('age')", true);
2427 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2431 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2432 v8::HandleScope scope(CcTest::isolate());
2433 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2434 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2436 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2437 CompileRun("var obj = new Obj;"
2438 "function setter(i) { this.accessor_age = i; };"
2439 "function getter() { return this.accessor_age; };"
2440 "function setAge(i) { obj.age = i; };"
2441 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2442 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2443 // All i >= 10000 go to the accessor.
2444 ExpectInt32("obj.accessor_age", 10000);
2445 // The last i goes to the interceptor.
2446 ExpectInt32("obj.interceptor_age", 9999);
2447 // The installed JavaScript getter is still intact.
2448 // This last part is a regression test for issue 1651 and relies on the fact
2449 // that both interceptor and accessor are being installed on the same object.
2450 ExpectInt32("obj.age", 10000);
2451 ExpectBoolean("obj.hasOwnProperty('age')", true);
2452 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2456 THREADED_TEST(SwitchFromInterceptorToProperty) {
2457 v8::HandleScope scope(CcTest::isolate());
2458 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2459 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2460 child->Inherit(parent);
2461 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2463 env->Global()->Set(v8_str("Child"), child->GetFunction());
2464 CompileRun("var child = new Child;"
2465 "function setAge(i){ child.age = i; };"
2466 "for(var i = 0; i <= 10000; i++) setAge(i);");
2467 // All i < 10000 go to the interceptor.
2468 ExpectInt32("child.interceptor_age", 9999);
2469 // The last i goes to child's own property.
2470 ExpectInt32("child.age", 10000);
2474 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2475 v8::HandleScope scope(CcTest::isolate());
2476 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2477 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2478 child->Inherit(parent);
2479 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2481 env->Global()->Set(v8_str("Child"), child->GetFunction());
2482 CompileRun("var child = new Child;"
2483 "function setAge(i){ child.age = i; };"
2484 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2485 // All i >= 10000 go to child's own property.
2486 ExpectInt32("child.age", 10000);
2487 // The last i goes to the interceptor.
2488 ExpectInt32("child.interceptor_age", 9999);
2492 THREADED_TEST(NamedPropertyHandlerGetter) {
2493 echo_named_call_count = 0;
2494 v8::HandleScope scope(CcTest::isolate());
2495 v8::Handle<v8::FunctionTemplate> templ =
2496 v8::FunctionTemplate::New(CcTest::isolate());
2497 templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2498 EchoNamedProperty, 0, 0, 0, 0, v8_str("data")));
2500 env->Global()->Set(v8_str("obj"),
2501 templ->GetFunction()->NewInstance());
2502 CHECK_EQ(echo_named_call_count, 0);
2503 v8_compile("obj.x")->Run();
2504 CHECK_EQ(echo_named_call_count, 1);
2505 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2506 v8::Handle<Value> str = CompileRun(code);
2507 String::Utf8Value value(str);
2508 CHECK_EQ(*value, "oddlepoddle");
2509 // Check default behavior
2510 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2511 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2512 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2516 int echo_indexed_call_count = 0;
2519 static void EchoIndexedProperty(
2521 const v8::PropertyCallbackInfo<v8::Value>& info) {
2522 ApiTestFuzzer::Fuzz();
2523 CHECK_EQ(v8_num(637), info.Data());
2524 echo_indexed_call_count++;
2525 info.GetReturnValue().Set(v8_num(index));
2529 THREADED_TEST(IndexedPropertyHandlerGetter) {
2530 v8::Isolate* isolate = CcTest::isolate();
2531 v8::HandleScope scope(isolate);
2532 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2533 templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2534 EchoIndexedProperty, 0, 0, 0, 0, v8_num(637)));
2536 env->Global()->Set(v8_str("obj"),
2537 templ->GetFunction()->NewInstance());
2538 Local<Script> script = v8_compile("obj[900]");
2539 CHECK_EQ(script->Run()->Int32Value(), 900);
2543 v8::Handle<v8::Object> bottom;
2545 static void CheckThisIndexedPropertyHandler(
2547 const v8::PropertyCallbackInfo<v8::Value>& info) {
2548 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2549 ApiTestFuzzer::Fuzz();
2550 CHECK(info.This()->Equals(bottom));
2553 static void CheckThisNamedPropertyHandler(
2554 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2555 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2556 ApiTestFuzzer::Fuzz();
2557 CHECK(info.This()->Equals(bottom));
2560 void CheckThisIndexedPropertySetter(
2563 const v8::PropertyCallbackInfo<v8::Value>& info) {
2564 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2565 ApiTestFuzzer::Fuzz();
2566 CHECK(info.This()->Equals(bottom));
2570 void CheckThisNamedPropertySetter(
2571 Local<Name> property, Local<Value> value,
2572 const v8::PropertyCallbackInfo<v8::Value>& info) {
2573 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2574 ApiTestFuzzer::Fuzz();
2575 CHECK(info.This()->Equals(bottom));
2578 void CheckThisIndexedPropertyQuery(
2580 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2581 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2582 ApiTestFuzzer::Fuzz();
2583 CHECK(info.This()->Equals(bottom));
2587 void CheckThisNamedPropertyQuery(
2588 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
2589 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2590 ApiTestFuzzer::Fuzz();
2591 CHECK(info.This()->Equals(bottom));
2595 void CheckThisIndexedPropertyDeleter(
2597 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2598 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2599 ApiTestFuzzer::Fuzz();
2600 CHECK(info.This()->Equals(bottom));
2604 void CheckThisNamedPropertyDeleter(
2605 Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2606 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2607 ApiTestFuzzer::Fuzz();
2608 CHECK(info.This()->Equals(bottom));
2612 void CheckThisIndexedPropertyEnumerator(
2613 const v8::PropertyCallbackInfo<v8::Array>& info) {
2614 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2615 ApiTestFuzzer::Fuzz();
2616 CHECK(info.This()->Equals(bottom));
2620 void CheckThisNamedPropertyEnumerator(
2621 const v8::PropertyCallbackInfo<v8::Array>& info) {
2622 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2623 ApiTestFuzzer::Fuzz();
2624 CHECK(info.This()->Equals(bottom));
2628 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2630 v8::Isolate* isolate = env->GetIsolate();
2631 v8::HandleScope scope(isolate);
2633 // Set up a prototype chain with three interceptors.
2634 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2635 templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
2636 CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
2637 CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
2638 CheckThisIndexedPropertyEnumerator));
2640 templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2641 CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
2642 CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
2643 CheckThisNamedPropertyEnumerator));
2645 bottom = templ->GetFunction()->NewInstance();
2646 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2647 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2649 bottom->SetPrototype(middle);
2650 middle->SetPrototype(top);
2651 env->Global()->Set(v8_str("obj"), bottom);
2653 // Indexed and named get.
2654 CompileRun("obj[0]");
2655 CompileRun("obj.x");
2657 // Indexed and named set.
2658 CompileRun("obj[1] = 42");
2659 CompileRun("obj.y = 42");
2661 // Indexed and named query.
2662 CompileRun("0 in obj");
2663 CompileRun("'x' in obj");
2665 // Indexed and named deleter.
2666 CompileRun("delete obj[0]");
2667 CompileRun("delete obj.x");
2670 CompileRun("for (var p in obj) ;");
2674 static void PrePropertyHandlerGet(
2675 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2676 ApiTestFuzzer::Fuzz();
2677 if (v8_str("pre")->Equals(key)) {
2678 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2683 static void PrePropertyHandlerQuery(
2684 Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
2685 if (v8_str("pre")->Equals(key)) {
2686 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2691 THREADED_TEST(PrePropertyHandler) {
2692 v8::Isolate* isolate = CcTest::isolate();
2693 v8::HandleScope scope(isolate);
2694 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2695 desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
2696 PrePropertyHandlerGet, 0, PrePropertyHandlerQuery));
2697 LocalContext env(NULL, desc->InstanceTemplate());
2698 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2699 v8::Handle<Value> result_pre = CompileRun("pre");
2700 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2701 v8::Handle<Value> result_on = CompileRun("on");
2702 CHECK_EQ(v8_str("Object: on"), result_on);
2703 v8::Handle<Value> result_post = CompileRun("post");
2704 CHECK(result_post.IsEmpty());
2708 THREADED_TEST(UndefinedIsNotEnumerable) {
2710 v8::HandleScope scope(env->GetIsolate());
2711 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2712 CHECK(result->IsFalse());
2716 v8::Handle<Script> call_recursively_script;
2717 static const int kTargetRecursionDepth = 200; // near maximum
2720 static void CallScriptRecursivelyCall(
2721 const v8::FunctionCallbackInfo<v8::Value>& args) {
2722 ApiTestFuzzer::Fuzz();
2723 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2724 if (depth == kTargetRecursionDepth) return;
2725 args.This()->Set(v8_str("depth"),
2726 v8::Integer::New(args.GetIsolate(), depth + 1));
2727 args.GetReturnValue().Set(call_recursively_script->Run());
2731 static void CallFunctionRecursivelyCall(
2732 const v8::FunctionCallbackInfo<v8::Value>& args) {
2733 ApiTestFuzzer::Fuzz();
2734 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2735 if (depth == kTargetRecursionDepth) {
2736 printf("[depth = %d]\n", depth);
2739 args.This()->Set(v8_str("depth"),
2740 v8::Integer::New(args.GetIsolate(), depth + 1));
2741 v8::Handle<Value> function =
2742 args.This()->Get(v8_str("callFunctionRecursively"));
2743 args.GetReturnValue().Set(
2744 function.As<Function>()->Call(args.This(), 0, NULL));
2748 THREADED_TEST(DeepCrossLanguageRecursion) {
2749 v8::Isolate* isolate = CcTest::isolate();
2750 v8::HandleScope scope(isolate);
2751 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2752 global->Set(v8_str("callScriptRecursively"),
2753 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2754 global->Set(v8_str("callFunctionRecursively"),
2755 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2756 LocalContext env(NULL, global);
2758 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2759 call_recursively_script = v8_compile("callScriptRecursively()");
2760 call_recursively_script->Run();
2761 call_recursively_script = v8::Handle<Script>();
2763 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2764 CompileRun("callFunctionRecursively()");
2768 static void ThrowingPropertyHandlerGet(
2769 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
2770 // Since this interceptor is used on "with" objects, the runtime will look up
2771 // @@unscopables. Punt.
2772 if (key->IsSymbol()) return;
2773 ApiTestFuzzer::Fuzz();
2774 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2778 static void ThrowingPropertyHandlerSet(
2779 Local<Name> key, Local<Value>,
2780 const v8::PropertyCallbackInfo<v8::Value>& info) {
2781 info.GetIsolate()->ThrowException(key);
2782 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2786 THREADED_TEST(CallbackExceptionRegression) {
2787 v8::Isolate* isolate = CcTest::isolate();
2788 v8::HandleScope scope(isolate);
2789 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2790 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
2791 ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
2793 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2794 v8::Handle<Value> otto = CompileRun(
2795 "try { with (obj) { otto; } } catch (e) { e; }");
2796 CHECK_EQ(v8_str("otto"), otto);
2797 v8::Handle<Value> netto = CompileRun(
2798 "try { with (obj) { netto = 4; } } catch (e) { e; }");
2799 CHECK_EQ(v8_str("netto"), netto);
2803 THREADED_TEST(FunctionPrototype) {
2804 v8::Isolate* isolate = CcTest::isolate();
2805 v8::HandleScope scope(isolate);
2806 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2807 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2809 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2810 Local<Script> script = v8_compile("Foo.prototype.plak");
2811 CHECK_EQ(script->Run()->Int32Value(), 321);
2815 THREADED_TEST(InternalFields) {
2817 v8::Isolate* isolate = env->GetIsolate();
2818 v8::HandleScope scope(isolate);
2820 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2821 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2822 instance_templ->SetInternalFieldCount(1);
2823 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2824 CHECK_EQ(1, obj->InternalFieldCount());
2825 CHECK(obj->GetInternalField(0)->IsUndefined());
2826 obj->SetInternalField(0, v8_num(17));
2827 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2831 THREADED_TEST(GlobalObjectInternalFields) {
2832 v8::Isolate* isolate = CcTest::isolate();
2833 v8::HandleScope scope(isolate);
2834 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2835 global_template->SetInternalFieldCount(1);
2836 LocalContext env(NULL, global_template);
2837 v8::Handle<v8::Object> global_proxy = env->Global();
2838 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2839 CHECK_EQ(1, global->InternalFieldCount());
2840 CHECK(global->GetInternalField(0)->IsUndefined());
2841 global->SetInternalField(0, v8_num(17));
2842 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2846 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2848 v8::HandleScope scope(CcTest::isolate());
2850 v8::Local<v8::Object> global = env->Global();
2851 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2852 CHECK(global->HasRealIndexedProperty(0));
2856 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2858 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2859 obj->SetAlignedPointerInInternalField(0, value);
2860 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2861 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2865 THREADED_TEST(InternalFieldsAlignedPointers) {
2867 v8::Isolate* isolate = env->GetIsolate();
2868 v8::HandleScope scope(isolate);
2870 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2871 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2872 instance_templ->SetInternalFieldCount(1);
2873 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2874 CHECK_EQ(1, obj->InternalFieldCount());
2876 CheckAlignedPointerInInternalField(obj, NULL);
2878 int* heap_allocated = new int[100];
2879 CheckAlignedPointerInInternalField(obj, heap_allocated);
2880 delete[] heap_allocated;
2882 int stack_allocated[100];
2883 CheckAlignedPointerInInternalField(obj, stack_allocated);
2885 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2886 CheckAlignedPointerInInternalField(obj, huge);
2888 v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2889 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2890 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2894 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2897 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2898 (*env)->SetAlignedPointerInEmbedderData(index, value);
2899 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2900 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2904 static void* AlignedTestPointer(int i) {
2905 return reinterpret_cast<void*>(i * 1234);
2909 THREADED_TEST(EmbedderDataAlignedPointers) {
2911 v8::HandleScope scope(env->GetIsolate());
2913 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2915 int* heap_allocated = new int[100];
2916 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2917 delete[] heap_allocated;
2919 int stack_allocated[100];
2920 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2922 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2923 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2925 // Test growing of the embedder data's backing store.
2926 for (int i = 0; i < 100; i++) {
2927 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2929 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2930 for (int i = 0; i < 100; i++) {
2931 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2936 static void CheckEmbedderData(LocalContext* env,
2938 v8::Handle<Value> data) {
2939 (*env)->SetEmbedderData(index, data);
2940 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2944 THREADED_TEST(EmbedderData) {
2946 v8::Isolate* isolate = env->GetIsolate();
2947 v8::HandleScope scope(isolate);
2951 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2952 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2953 "over the lazy dog."));
2954 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2955 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2959 THREADED_TEST(GetIsolate) {
2961 v8::Isolate* isolate = env->GetIsolate();
2962 v8::HandleScope scope(isolate);
2963 Local<v8::Object> obj = v8::Object::New(isolate);
2964 CHECK_EQ(isolate, obj->GetIsolate());
2965 CHECK_EQ(isolate, CcTest::global()->GetIsolate());
2969 THREADED_TEST(IdentityHash) {
2971 v8::Isolate* isolate = env->GetIsolate();
2972 v8::HandleScope scope(isolate);
2974 // Ensure that the test starts with an fresh heap to test whether the hash
2975 // code is based on the address.
2976 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2977 Local<v8::Object> obj = v8::Object::New(isolate);
2978 int hash = obj->GetIdentityHash();
2979 int hash1 = obj->GetIdentityHash();
2980 CHECK_EQ(hash, hash1);
2981 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2982 // Since the identity hash is essentially a random number two consecutive
2983 // objects should not be assigned the same hash code. If the test below fails
2984 // the random number generator should be evaluated.
2985 CHECK_NE(hash, hash2);
2986 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2987 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2988 // Make sure that the identity hash is not based on the initial address of
2989 // the object alone. If the test below fails the random number generator
2990 // should be evaluated.
2991 CHECK_NE(hash, hash3);
2992 int hash4 = obj->GetIdentityHash();
2993 CHECK_EQ(hash, hash4);
2995 // Check identity hashes behaviour in the presence of JS accessors.
2996 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2998 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2999 Local<v8::Object> o1 = v8::Object::New(isolate);
3000 Local<v8::Object> o2 = v8::Object::New(isolate);
3001 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3005 "function cnst() { return 42; };\n"
3006 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
3007 Local<v8::Object> o1 = v8::Object::New(isolate);
3008 Local<v8::Object> o2 = v8::Object::New(isolate);
3009 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
3014 THREADED_TEST(GlobalProxyIdentityHash) {
3016 v8::Isolate* isolate = env->GetIsolate();
3017 v8::HandleScope scope(isolate);
3018 Handle<Object> global_proxy = env->Global();
3019 int hash1 = global_proxy->GetIdentityHash();
3020 // Hash should be retained after being detached.
3021 env->DetachGlobal();
3022 int hash2 = global_proxy->GetIdentityHash();
3023 CHECK_EQ(hash1, hash2);
3025 // Re-attach global proxy to a new context, hash should stay the same.
3026 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
3027 int hash3 = global_proxy->GetIdentityHash();
3028 CHECK_EQ(hash1, hash3);
3033 TEST(SymbolIdentityHash) {
3035 v8::Isolate* isolate = env->GetIsolate();
3036 v8::HandleScope scope(isolate);
3039 Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
3040 int hash = symbol->GetIdentityHash();
3041 int hash1 = symbol->GetIdentityHash();
3042 CHECK_EQ(hash, hash1);
3043 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3044 int hash3 = symbol->GetIdentityHash();
3045 CHECK_EQ(hash, hash3);
3049 v8::Handle<v8::Symbol> js_symbol =
3050 CompileRun("Symbol('foo')").As<v8::Symbol>();
3051 int hash = js_symbol->GetIdentityHash();
3052 int hash1 = js_symbol->GetIdentityHash();
3053 CHECK_EQ(hash, hash1);
3054 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3055 int hash3 = js_symbol->GetIdentityHash();
3056 CHECK_EQ(hash, hash3);
3061 TEST(StringIdentityHash) {
3063 v8::Isolate* isolate = env->GetIsolate();
3064 v8::HandleScope scope(isolate);
3066 Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
3067 int hash = str->GetIdentityHash();
3068 int hash1 = str->GetIdentityHash();
3069 CHECK_EQ(hash, hash1);
3070 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3071 int hash3 = str->GetIdentityHash();
3072 CHECK_EQ(hash, hash3);
3074 Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
3075 int hash4 = str2->GetIdentityHash();
3076 CHECK_EQ(hash, hash4);
3080 THREADED_TEST(SymbolProperties) {
3082 v8::Isolate* isolate = env->GetIsolate();
3083 v8::HandleScope scope(isolate);
3085 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3086 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
3087 v8::Local<v8::Symbol> sym2 =
3088 v8::Symbol::New(isolate, v8_str("my-symbol"));
3089 v8::Local<v8::Symbol> sym3 =
3090 v8::Symbol::New(isolate, v8_str("sym3"));
3092 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3094 // Check basic symbol functionality.
3095 CHECK(sym1->IsSymbol());
3096 CHECK(sym2->IsSymbol());
3097 CHECK(!obj->IsSymbol());
3099 CHECK(sym1->Equals(sym1));
3100 CHECK(sym2->Equals(sym2));
3101 CHECK(!sym1->Equals(sym2));
3102 CHECK(!sym2->Equals(sym1));
3103 CHECK(sym1->StrictEquals(sym1));
3104 CHECK(sym2->StrictEquals(sym2));
3105 CHECK(!sym1->StrictEquals(sym2));
3106 CHECK(!sym2->StrictEquals(sym1));
3108 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
3110 v8::Local<v8::Value> sym_val = sym2;
3111 CHECK(sym_val->IsSymbol());
3112 CHECK(sym_val->Equals(sym2));
3113 CHECK(sym_val->StrictEquals(sym2));
3114 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
3116 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
3117 CHECK(sym_obj->IsSymbolObject());
3118 CHECK(!sym2->IsSymbolObject());
3119 CHECK(!obj->IsSymbolObject());
3120 CHECK(!sym_obj->Equals(sym2));
3121 CHECK(!sym_obj->StrictEquals(sym2));
3122 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
3123 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
3125 // Make sure delete of a non-existent symbol property works.
3126 CHECK(obj->Delete(sym1));
3127 CHECK(!obj->Has(sym1));
3129 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
3130 CHECK(obj->Has(sym1));
3131 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
3132 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
3133 CHECK(obj->Has(sym1));
3134 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3135 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
3137 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
3138 int num_props = obj->GetPropertyNames()->Length();
3139 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
3140 v8::Integer::New(isolate, 20)));
3141 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3142 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
3144 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3146 CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
3147 CHECK(obj->Get(sym3)->IsUndefined());
3148 CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
3149 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3150 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3151 v8::Integer::New(isolate, 42)));
3153 // Add another property and delete it afterwards to force the object in
3155 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
3156 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3157 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
3158 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3159 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
3161 CHECK(obj->Has(sym1));
3162 CHECK(obj->Has(sym2));
3163 CHECK(obj->Has(sym3));
3164 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
3165 CHECK(obj->Delete(sym2));
3166 CHECK(obj->Has(sym1));
3167 CHECK(!obj->Has(sym2));
3168 CHECK(obj->Has(sym3));
3169 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
3170 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3171 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3172 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3173 v8::Integer::New(isolate, 42)));
3174 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
3176 // Symbol properties are inherited.
3177 v8::Local<v8::Object> child = v8::Object::New(isolate);
3178 child->SetPrototype(obj);
3179 CHECK(child->Has(sym1));
3180 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
3181 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3182 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3183 v8::Integer::New(isolate, 42)));
3184 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3188 THREADED_TEST(SymbolTemplateProperties) {
3190 v8::Isolate* isolate = env->GetIsolate();
3191 v8::HandleScope scope(isolate);
3192 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3193 v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3194 CHECK(!name.IsEmpty());
3195 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3196 v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
3197 CHECK(!new_instance.IsEmpty());
3198 CHECK(new_instance->Has(name));
3202 THREADED_TEST(PrivateProperties) {
3204 v8::Isolate* isolate = env->GetIsolate();
3205 v8::HandleScope scope(isolate);
3207 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3208 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3209 v8::Local<v8::Private> priv2 =
3210 v8::Private::New(isolate, v8_str("my-private"));
3212 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3214 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
3216 // Make sure delete of a non-existent private symbol property works.
3217 CHECK(obj->DeletePrivate(priv1));
3218 CHECK(!obj->HasPrivate(priv1));
3220 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
3221 CHECK(obj->HasPrivate(priv1));
3222 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
3223 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
3224 CHECK(obj->HasPrivate(priv1));
3225 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3227 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
3228 int num_props = obj->GetPropertyNames()->Length();
3229 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
3230 v8::Integer::New(isolate, 20)));
3231 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3232 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
3234 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3236 // Add another property and delete it afterwards to force the object in
3238 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
3239 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3240 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
3241 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3242 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3244 CHECK(obj->HasPrivate(priv1));
3245 CHECK(obj->HasPrivate(priv2));
3246 CHECK(obj->DeletePrivate(priv2));
3247 CHECK(obj->HasPrivate(priv1));
3248 CHECK(!obj->HasPrivate(priv2));
3249 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3250 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3252 // Private properties are inherited (for the time being).
3253 v8::Local<v8::Object> child = v8::Object::New(isolate);
3254 child->SetPrototype(obj);
3255 CHECK(child->HasPrivate(priv1));
3256 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
3257 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3261 THREADED_TEST(GlobalSymbols) {
3263 v8::Isolate* isolate = env->GetIsolate();
3264 v8::HandleScope scope(isolate);
3266 v8::Local<String> name = v8_str("my-symbol");
3267 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3268 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3269 CHECK(glob2->SameValue(glob));
3271 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3272 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3273 CHECK(glob_api2->SameValue(glob_api));
3274 CHECK(!glob_api->SameValue(glob));
3276 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3277 CHECK(!sym->SameValue(glob));
3279 CompileRun("var sym2 = Symbol.for('my-symbol')");
3280 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
3281 CHECK(sym2->SameValue(glob));
3282 CHECK(!sym2->SameValue(glob_api));
3286 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3289 v8::Isolate* isolate = env->GetIsolate();
3290 v8::HandleScope scope(isolate);
3292 v8::Local<v8::Symbol> symbol = getter(isolate);
3293 std::string script = std::string("var sym = ") + name;
3294 CompileRun(script.c_str());
3295 v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
3297 CHECK(!value.IsEmpty());
3298 CHECK(!symbol.IsEmpty());
3299 CHECK(value->SameValue(symbol));
3303 THREADED_TEST(WellKnownSymbols) {
3304 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3305 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3309 THREADED_TEST(GlobalPrivates) {
3311 v8::Isolate* isolate = env->GetIsolate();
3312 v8::HandleScope scope(isolate);
3314 v8::Local<String> name = v8_str("my-private");
3315 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3316 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3317 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
3319 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3320 CHECK(obj->HasPrivate(glob2));
3322 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3323 CHECK(!obj->HasPrivate(priv));
3325 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
3326 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
3327 CHECK(!obj->Has(intern));
3331 class ScopedArrayBufferContents {
3333 explicit ScopedArrayBufferContents(
3334 const v8::ArrayBuffer::Contents& contents)
3335 : contents_(contents) {}
3336 ~ScopedArrayBufferContents() { free(contents_.Data()); }
3337 void* Data() const { return contents_.Data(); }
3338 size_t ByteLength() const { return contents_.ByteLength(); }
3340 const v8::ArrayBuffer::Contents contents_;
3343 template <typename T>
3344 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
3345 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3346 for (int i = 0; i < value->InternalFieldCount(); i++) {
3347 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
3352 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3354 v8::Isolate* isolate = env->GetIsolate();
3355 v8::HandleScope handle_scope(isolate);
3357 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3358 CheckInternalFieldsAreZero(ab);
3359 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3360 CHECK(!ab->IsExternal());
3361 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3363 ScopedArrayBufferContents ab_contents(ab->Externalize());
3364 CHECK(ab->IsExternal());
3366 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3367 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3368 DCHECK(data != NULL);
3369 env->Global()->Set(v8_str("ab"), ab);
3371 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3372 CHECK_EQ(1024, result->Int32Value());
3374 result = CompileRun("var u8 = new Uint8Array(ab);"
3378 CHECK_EQ(1024, result->Int32Value());
3379 CHECK_EQ(0xFF, data[0]);
3380 CHECK_EQ(0xAA, data[1]);
3383 result = CompileRun("u8[0] + u8[1]");
3384 CHECK_EQ(0xDD, result->Int32Value());
3388 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3390 v8::Isolate* isolate = env->GetIsolate();
3391 v8::HandleScope handle_scope(isolate);
3394 v8::Local<v8::Value> result =
3395 CompileRun("var ab1 = new ArrayBuffer(2);"
3396 "var u8_a = new Uint8Array(ab1);"
3398 "u8_a[1] = 0xFF; u8_a.buffer");
3399 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3400 CheckInternalFieldsAreZero(ab1);
3401 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3402 CHECK(!ab1->IsExternal());
3403 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3404 CHECK(ab1->IsExternal());
3406 result = CompileRun("ab1.byteLength");
3407 CHECK_EQ(2, result->Int32Value());
3408 result = CompileRun("u8_a[0]");
3409 CHECK_EQ(0xAA, result->Int32Value());
3410 result = CompileRun("u8_a[1]");
3411 CHECK_EQ(0xFF, result->Int32Value());
3412 result = CompileRun("var u8_b = new Uint8Array(ab1);"
3415 CHECK_EQ(0xBB, result->Int32Value());
3416 result = CompileRun("u8_b[1]");
3417 CHECK_EQ(0xFF, result->Int32Value());
3419 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3420 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3421 CHECK_EQ(0xBB, ab1_data[0]);
3422 CHECK_EQ(0xFF, ab1_data[1]);
3425 result = CompileRun("u8_a[0] + u8_a[1]");
3426 CHECK_EQ(0xDD, result->Int32Value());
3430 THREADED_TEST(ArrayBuffer_External) {
3432 v8::Isolate* isolate = env->GetIsolate();
3433 v8::HandleScope handle_scope(isolate);
3435 i::ScopedVector<uint8_t> my_data(100);
3436 memset(my_data.start(), 0, 100);
3437 Local<v8::ArrayBuffer> ab3 =
3438 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3439 CheckInternalFieldsAreZero(ab3);
3440 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3441 CHECK(ab3->IsExternal());
3443 env->Global()->Set(v8_str("ab3"), ab3);
3445 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3446 CHECK_EQ(100, result->Int32Value());
3448 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3452 CHECK_EQ(100, result->Int32Value());
3453 CHECK_EQ(0xBB, my_data[0]);
3454 CHECK_EQ(0xCC, my_data[1]);
3457 result = CompileRun("u8_b[0] + u8_b[1]");
3458 CHECK_EQ(0xDD, result->Int32Value());
3462 THREADED_TEST(ArrayBuffer_DisableNeuter) {
3464 v8::Isolate* isolate = env->GetIsolate();
3465 v8::HandleScope handle_scope(isolate);
3467 i::ScopedVector<uint8_t> my_data(100);
3468 memset(my_data.start(), 0, 100);
3469 Local<v8::ArrayBuffer> ab =
3470 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3471 CHECK(ab->IsNeuterable());
3473 i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3474 buf->set_is_neuterable(false);
3476 CHECK(!ab->IsNeuterable());
3480 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3481 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3482 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3486 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3487 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3488 CHECK_EQ(0, static_cast<int>(ta->Length()));
3489 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3493 static void CheckIsTypedArrayVarNeutered(const char* name) {
3494 i::ScopedVector<char> source(1024);
3496 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3498 CHECK(CompileRun(source.start())->IsTrue());
3499 v8::Handle<v8::TypedArray> ta =
3500 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3501 CheckIsNeutered(ta);
3505 template <typename TypedArray, int kElementSize>
3506 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3509 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3510 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3511 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3512 CHECK_EQ(length, static_cast<int>(ta->Length()));
3513 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3518 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3520 v8::Isolate* isolate = env->GetIsolate();
3521 v8::HandleScope handle_scope(isolate);
3523 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3525 v8::Handle<v8::Uint8Array> u8a =
3526 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3527 v8::Handle<v8::Uint8ClampedArray> u8c =
3528 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3529 v8::Handle<v8::Int8Array> i8a =
3530 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3532 v8::Handle<v8::Uint16Array> u16a =
3533 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3534 v8::Handle<v8::Int16Array> i16a =
3535 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3537 v8::Handle<v8::Uint32Array> u32a =
3538 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3539 v8::Handle<v8::Int32Array> i32a =
3540 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3542 v8::Handle<v8::Float32Array> f32a =
3543 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3544 v8::Handle<v8::Float64Array> f64a =
3545 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3547 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3548 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3549 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3550 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3552 ScopedArrayBufferContents contents(buffer->Externalize());
3554 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3555 CheckIsNeutered(u8a);
3556 CheckIsNeutered(u8c);
3557 CheckIsNeutered(i8a);
3558 CheckIsNeutered(u16a);
3559 CheckIsNeutered(i16a);
3560 CheckIsNeutered(u32a);
3561 CheckIsNeutered(i32a);
3562 CheckIsNeutered(f32a);
3563 CheckIsNeutered(f64a);
3564 CheckDataViewIsNeutered(dv);
3568 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3570 v8::Isolate* isolate = env->GetIsolate();
3571 v8::HandleScope handle_scope(isolate);
3574 "var ab = new ArrayBuffer(1024);"
3575 "var u8a = new Uint8Array(ab, 1, 1023);"
3576 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3577 "var i8a = new Int8Array(ab, 1, 1023);"
3578 "var u16a = new Uint16Array(ab, 2, 511);"
3579 "var i16a = new Int16Array(ab, 2, 511);"
3580 "var u32a = new Uint32Array(ab, 4, 255);"
3581 "var i32a = new Int32Array(ab, 4, 255);"
3582 "var f32a = new Float32Array(ab, 4, 255);"
3583 "var f64a = new Float64Array(ab, 8, 127);"
3584 "var dv = new DataView(ab, 1, 1023);");
3586 v8::Handle<v8::ArrayBuffer> ab =
3587 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3589 v8::Handle<v8::DataView> dv =
3590 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3592 ScopedArrayBufferContents contents(ab->Externalize());
3594 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3595 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3597 CheckIsTypedArrayVarNeutered("u8a");
3598 CheckIsTypedArrayVarNeutered("u8c");
3599 CheckIsTypedArrayVarNeutered("i8a");
3600 CheckIsTypedArrayVarNeutered("u16a");
3601 CheckIsTypedArrayVarNeutered("i16a");
3602 CheckIsTypedArrayVarNeutered("u32a");
3603 CheckIsTypedArrayVarNeutered("i32a");
3604 CheckIsTypedArrayVarNeutered("f32a");
3605 CheckIsTypedArrayVarNeutered("f64a");
3607 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3608 CheckDataViewIsNeutered(dv);
3613 THREADED_TEST(HiddenProperties) {
3615 v8::Isolate* isolate = env->GetIsolate();
3616 v8::HandleScope scope(isolate);
3618 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3619 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3620 v8::Local<v8::String> empty = v8_str("");
3621 v8::Local<v8::String> prop_name = v8_str("prop_name");
3623 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3625 // Make sure delete of a non-existent hidden value works
3626 CHECK(obj->DeleteHiddenValue(key));
3628 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3629 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3630 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3631 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3633 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3635 // Make sure we do not find the hidden property.
3636 CHECK(!obj->Has(empty));
3637 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3638 CHECK(obj->Get(empty)->IsUndefined());
3639 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3640 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3641 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3642 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3644 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3646 // Add another property and delete it afterwards to force the object in
3648 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3649 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3650 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3651 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3652 CHECK(obj->Delete(prop_name));
3653 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3655 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3657 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3658 CHECK(obj->GetHiddenValue(key).IsEmpty());
3660 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3661 CHECK(obj->DeleteHiddenValue(key));
3662 CHECK(obj->GetHiddenValue(key).IsEmpty());
3666 THREADED_TEST(Regress97784) {
3667 // Regression test for crbug.com/97784
3668 // Messing with the Object.prototype should not have effect on
3669 // hidden properties.
3671 v8::HandleScope scope(env->GetIsolate());
3673 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3674 v8::Local<v8::String> key = v8_str("hidden");
3677 "set_called = false;"
3678 "Object.defineProperty("
3679 " Object.prototype,"
3681 " {get: function() { return 45; },"
3682 " set: function() { set_called = true; }})");
3684 CHECK(obj->GetHiddenValue(key).IsEmpty());
3685 // Make sure that the getter and setter from Object.prototype is not invoked.
3686 // If it did we would have full access to the hidden properties in
3688 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3689 ExpectFalse("set_called");
3690 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3694 static bool interceptor_for_hidden_properties_called;
3695 static void InterceptorForHiddenProperties(
3696 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3697 interceptor_for_hidden_properties_called = true;
3701 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3702 LocalContext context;
3703 v8::Isolate* isolate = context->GetIsolate();
3704 v8::HandleScope scope(isolate);
3706 interceptor_for_hidden_properties_called = false;
3708 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3710 // Associate an interceptor with an object and start setting hidden values.
3711 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3712 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3713 instance_templ->SetHandler(
3714 v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
3715 Local<v8::Function> function = fun_templ->GetFunction();
3716 Local<v8::Object> obj = function->NewInstance();
3717 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3718 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3719 CHECK(!interceptor_for_hidden_properties_called);
3723 THREADED_TEST(External) {
3724 v8::HandleScope scope(CcTest::isolate());
3726 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3728 env->Global()->Set(v8_str("ext"), ext);
3729 Local<Value> reext_obj = CompileRun("this.ext");
3730 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3731 int* ptr = static_cast<int*>(reext->Value());
3736 // Make sure unaligned pointers are wrapped properly.
3737 char* data = i::StrDup("0123456789");
3738 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3739 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3740 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3741 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3743 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3744 CHECK_EQ('0', *char_ptr);
3745 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3746 CHECK_EQ('1', *char_ptr);
3747 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3748 CHECK_EQ('2', *char_ptr);
3749 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3750 CHECK_EQ('3', *char_ptr);
3751 i::DeleteArray(data);
3755 THREADED_TEST(GlobalHandle) {
3756 v8::Isolate* isolate = CcTest::isolate();
3757 v8::Persistent<String> global;
3759 v8::HandleScope scope(isolate);
3760 global.Reset(isolate, v8_str("str"));
3763 v8::HandleScope scope(isolate);
3764 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3768 v8::HandleScope scope(isolate);
3769 global.Reset(isolate, v8_str("str"));
3772 v8::HandleScope scope(isolate);
3773 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3779 THREADED_TEST(ResettingGlobalHandle) {
3780 v8::Isolate* isolate = CcTest::isolate();
3781 v8::Persistent<String> global;
3783 v8::HandleScope scope(isolate);
3784 global.Reset(isolate, v8_str("str"));
3786 v8::internal::GlobalHandles* global_handles =
3787 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3788 int initial_handle_count = global_handles->global_handles_count();
3790 v8::HandleScope scope(isolate);
3791 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3794 v8::HandleScope scope(isolate);
3795 global.Reset(isolate, v8_str("longer"));
3797 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3799 v8::HandleScope scope(isolate);
3800 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3803 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3807 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3808 v8::Isolate* isolate = CcTest::isolate();
3809 v8::Persistent<String> global;
3811 v8::HandleScope scope(isolate);
3812 global.Reset(isolate, v8_str("str"));
3814 v8::internal::GlobalHandles* global_handles =
3815 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3816 int initial_handle_count = global_handles->global_handles_count();
3818 v8::HandleScope scope(isolate);
3819 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3822 v8::HandleScope scope(isolate);
3823 Local<String> empty;
3824 global.Reset(isolate, empty);
3826 CHECK(global.IsEmpty());
3827 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3832 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3833 return unique.Pass();
3838 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3839 const v8::Persistent<T> & global) {
3840 v8::UniquePersistent<String> unique(isolate, global);
3841 return unique.Pass();
3845 THREADED_TEST(UniquePersistent) {
3846 v8::Isolate* isolate = CcTest::isolate();
3847 v8::Persistent<String> global;
3849 v8::HandleScope scope(isolate);
3850 global.Reset(isolate, v8_str("str"));
3852 v8::internal::GlobalHandles* global_handles =
3853 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3854 int initial_handle_count = global_handles->global_handles_count();
3856 v8::UniquePersistent<String> unique(isolate, global);
3857 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3858 // Test assignment via Pass
3860 v8::UniquePersistent<String> copy = unique.Pass();
3861 CHECK(unique.IsEmpty());
3862 CHECK(copy == global);
3863 CHECK_EQ(initial_handle_count + 1,
3864 global_handles->global_handles_count());
3865 unique = copy.Pass();
3867 // Test ctor via Pass
3869 v8::UniquePersistent<String> copy(unique.Pass());
3870 CHECK(unique.IsEmpty());
3871 CHECK(copy == global);
3872 CHECK_EQ(initial_handle_count + 1,
3873 global_handles->global_handles_count());
3874 unique = copy.Pass();
3876 // Test pass through function call
3878 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3879 CHECK(unique.IsEmpty());
3880 CHECK(copy == global);
3881 CHECK_EQ(initial_handle_count + 1,
3882 global_handles->global_handles_count());
3883 unique = copy.Pass();
3885 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3887 // Test pass from function call
3889 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3890 CHECK(unique == global);
3891 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3893 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3898 template<typename K, typename V>
3899 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3901 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3903 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3904 struct WeakCallbackDataType {
3908 static WeakCallbackDataType* WeakCallbackParameter(
3909 MapType* map, const K& key, Local<V> value) {
3910 WeakCallbackDataType* data = new WeakCallbackDataType;
3915 static MapType* MapFromWeakCallbackData(
3916 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3917 return data.GetParameter()->map;
3919 static K KeyFromWeakCallbackData(
3920 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3921 return data.GetParameter()->key;
3923 static void DisposeCallbackData(WeakCallbackDataType* data) {
3926 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3931 template<typename Map>
3932 static void TestPersistentValueMap() {
3934 v8::Isolate* isolate = env->GetIsolate();
3936 v8::internal::GlobalHandles* global_handles =
3937 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3938 int initial_handle_count = global_handles->global_handles_count();
3939 CHECK_EQ(0, static_cast<int>(map.Size()));
3941 HandleScope scope(isolate);
3942 Local<v8::Object> obj = map.Get(7);
3943 CHECK(obj.IsEmpty());
3944 Local<v8::Object> expected = v8::Object::New(isolate);
3945 map.Set(7, expected);
3946 CHECK_EQ(1, static_cast<int>(map.Size()));
3948 CHECK_EQ(expected, obj);
3950 typename Map::PersistentValueReference ref = map.GetReference(7);
3951 CHECK_EQ(expected, ref.NewLocal(isolate));
3953 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3954 CHECK_EQ(0, static_cast<int>(map.Size()));
3955 CHECK(expected == removed);
3956 removed = map.Remove(7);
3957 CHECK(removed.IsEmpty());
3958 map.Set(8, expected);
3959 CHECK_EQ(1, static_cast<int>(map.Size()));
3960 map.Set(8, expected);
3961 CHECK_EQ(1, static_cast<int>(map.Size()));
3963 typename Map::PersistentValueReference ref;
3964 Local<v8::Object> expected2 = v8::Object::New(isolate);
3965 removed = map.Set(8,
3966 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3967 CHECK_EQ(1, static_cast<int>(map.Size()));
3968 CHECK(expected == removed);
3969 CHECK_EQ(expected2, ref.NewLocal(isolate));
3972 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3974 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3975 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3979 CHECK_EQ(0, static_cast<int>(map.Size()));
3980 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3984 TEST(PersistentValueMap) {
3985 // Default case, w/o weak callbacks:
3986 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3988 // Custom traits with weak callbacks:
3989 typedef v8::PersistentValueMap<int, v8::Object,
3990 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3991 TestPersistentValueMap<WeakPersistentValueMap>();
3995 TEST(PersistentValueVector) {
3997 v8::Isolate* isolate = env->GetIsolate();
3998 v8::internal::GlobalHandles* global_handles =
3999 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
4000 int handle_count = global_handles->global_handles_count();
4001 HandleScope scope(isolate);
4003 v8::PersistentValueVector<v8::Object> vector(isolate);
4005 Local<v8::Object> obj1 = v8::Object::New(isolate);
4006 Local<v8::Object> obj2 = v8::Object::New(isolate);
4007 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
4009 CHECK(vector.IsEmpty());
4010 CHECK_EQ(0, static_cast<int>(vector.Size()));
4012 vector.ReserveCapacity(3);
4013 CHECK(vector.IsEmpty());
4015 vector.Append(obj1);
4016 vector.Append(obj2);
4017 vector.Append(obj1);
4018 vector.Append(obj3.Pass());
4019 vector.Append(obj1);
4021 CHECK(!vector.IsEmpty());
4022 CHECK_EQ(5, static_cast<int>(vector.Size()));
4023 CHECK(obj3.IsEmpty());
4024 CHECK_EQ(obj1, vector.Get(0));
4025 CHECK_EQ(obj1, vector.Get(2));
4026 CHECK_EQ(obj1, vector.Get(4));
4027 CHECK_EQ(obj2, vector.Get(1));
4029 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
4032 CHECK(vector.IsEmpty());
4033 CHECK_EQ(0, static_cast<int>(vector.Size()));
4034 CHECK_EQ(handle_count, global_handles->global_handles_count());
4038 THREADED_TEST(GlobalHandleUpcast) {
4039 v8::Isolate* isolate = CcTest::isolate();
4040 v8::HandleScope scope(isolate);
4041 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
4042 v8::Persistent<String> global_string(isolate, local);
4043 v8::Persistent<Value>& global_value =
4044 v8::Persistent<Value>::Cast(global_string);
4045 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
4046 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
4047 global_string.Reset();
4051 THREADED_TEST(HandleEquality) {
4052 v8::Isolate* isolate = CcTest::isolate();
4053 v8::Persistent<String> global1;
4054 v8::Persistent<String> global2;
4056 v8::HandleScope scope(isolate);
4057 global1.Reset(isolate, v8_str("str"));
4058 global2.Reset(isolate, v8_str("str2"));
4060 CHECK_EQ(global1 == global1, true);
4061 CHECK_EQ(global1 != global1, false);
4063 v8::HandleScope scope(isolate);
4064 Local<String> local1 = Local<String>::New(isolate, global1);
4065 Local<String> local2 = Local<String>::New(isolate, global2);
4067 CHECK_EQ(global1 == local1, true);
4068 CHECK_EQ(global1 != local1, false);
4069 CHECK_EQ(local1 == global1, true);
4070 CHECK_EQ(local1 != global1, false);
4072 CHECK_EQ(global1 == local2, false);
4073 CHECK_EQ(global1 != local2, true);
4074 CHECK_EQ(local2 == global1, false);
4075 CHECK_EQ(local2 != global1, true);
4077 CHECK_EQ(local1 == local2, false);
4078 CHECK_EQ(local1 != local2, true);
4080 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
4081 CHECK_EQ(local1 == anotherLocal1, true);
4082 CHECK_EQ(local1 != anotherLocal1, false);
4089 THREADED_TEST(LocalHandle) {
4090 v8::HandleScope scope(CcTest::isolate());
4091 v8::Local<String> local =
4092 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
4093 CHECK_EQ(local->Length(), 3);
4097 class WeakCallCounter {
4099 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
4100 int id() { return id_; }
4101 void increment() { number_of_weak_calls_++; }
4102 int NumberOfWeakCalls() { return number_of_weak_calls_; }
4105 int number_of_weak_calls_;
4109 template<typename T>
4110 struct WeakCallCounterAndPersistent {
4111 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
4112 : counter(counter) {}
4113 WeakCallCounter* counter;
4114 v8::Persistent<T> handle;
4118 template <typename T>
4119 static void WeakPointerCallback(
4120 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
4121 CHECK_EQ(1234, data.GetParameter()->counter->id());
4122 data.GetParameter()->counter->increment();
4123 data.GetParameter()->handle.Reset();
4127 template<typename T>
4128 static UniqueId MakeUniqueId(const Persistent<T>& p) {
4129 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
4133 THREADED_TEST(ApiObjectGroups) {
4135 v8::Isolate* iso = env->GetIsolate();
4136 HandleScope scope(iso);
4138 WeakCallCounter counter(1234);
4140 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4141 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4142 WeakCallCounterAndPersistent<Value> g1c1(&counter);
4143 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4144 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4145 WeakCallCounterAndPersistent<Value> g2c1(&counter);
4148 HandleScope scope(iso);
4149 g1s1.handle.Reset(iso, Object::New(iso));
4150 g1s2.handle.Reset(iso, Object::New(iso));
4151 g1c1.handle.Reset(iso, Object::New(iso));
4152 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4153 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4154 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4156 g2s1.handle.Reset(iso, Object::New(iso));
4157 g2s2.handle.Reset(iso, Object::New(iso));
4158 g2c1.handle.Reset(iso, Object::New(iso));
4159 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4160 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4161 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4164 WeakCallCounterAndPersistent<Value> root(&counter);
4165 root.handle.Reset(iso, g1s1.handle); // make a root.
4167 // Connect group 1 and 2, make a cycle.
4169 HandleScope scope(iso);
4170 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
4171 Set(0, Local<Value>::New(iso, g2s2.handle)));
4172 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
4173 Set(0, Local<Value>::New(iso, g1s1.handle)));
4177 UniqueId id1 = MakeUniqueId(g1s1.handle);
4178 UniqueId id2 = MakeUniqueId(g2s2.handle);
4179 iso->SetObjectGroupId(g1s1.handle, id1);
4180 iso->SetObjectGroupId(g1s2.handle, id1);
4181 iso->SetReferenceFromGroup(id1, g1c1.handle);
4182 iso->SetObjectGroupId(g2s1.handle, id2);
4183 iso->SetObjectGroupId(g2s2.handle, id2);
4184 iso->SetReferenceFromGroup(id2, g2c1.handle);
4186 // Do a single full GC, ensure incremental marking is stopped.
4187 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4189 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4191 // All object should be alive.
4192 CHECK_EQ(0, counter.NumberOfWeakCalls());
4195 root.handle.SetWeak(&root, &WeakPointerCallback);
4196 // But make children strong roots---all the objects (except for children)
4197 // should be collectable now.
4198 g1c1.handle.ClearWeak();
4199 g2c1.handle.ClearWeak();
4201 // Groups are deleted, rebuild groups.
4203 UniqueId id1 = MakeUniqueId(g1s1.handle);
4204 UniqueId id2 = MakeUniqueId(g2s2.handle);
4205 iso->SetObjectGroupId(g1s1.handle, id1);
4206 iso->SetObjectGroupId(g1s2.handle, id1);
4207 iso->SetReferenceFromGroup(id1, g1c1.handle);
4208 iso->SetObjectGroupId(g2s1.handle, id2);
4209 iso->SetObjectGroupId(g2s2.handle, id2);
4210 iso->SetReferenceFromGroup(id2, g2c1.handle);
4213 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4215 // All objects should be gone. 5 global handles in total.
4216 CHECK_EQ(5, counter.NumberOfWeakCalls());
4218 // And now make children weak again and collect them.
4219 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4220 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4222 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4223 CHECK_EQ(7, counter.NumberOfWeakCalls());
4227 THREADED_TEST(ApiObjectGroupsForSubtypes) {
4229 v8::Isolate* iso = env->GetIsolate();
4230 HandleScope scope(iso);
4232 WeakCallCounter counter(1234);
4234 WeakCallCounterAndPersistent<Object> g1s1(&counter);
4235 WeakCallCounterAndPersistent<String> g1s2(&counter);
4236 WeakCallCounterAndPersistent<String> g1c1(&counter);
4237 WeakCallCounterAndPersistent<Object> g2s1(&counter);
4238 WeakCallCounterAndPersistent<String> g2s2(&counter);
4239 WeakCallCounterAndPersistent<String> g2c1(&counter);
4242 HandleScope scope(iso);
4243 g1s1.handle.Reset(iso, Object::New(iso));
4244 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
4245 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
4246 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4247 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4248 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4250 g2s1.handle.Reset(iso, Object::New(iso));
4251 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
4252 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
4253 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4254 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4255 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4258 WeakCallCounterAndPersistent<Value> root(&counter);
4259 root.handle.Reset(iso, g1s1.handle); // make a root.
4261 // Connect group 1 and 2, make a cycle.
4263 HandleScope scope(iso);
4264 CHECK(Local<Object>::New(iso, g1s1.handle)
4265 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
4266 CHECK(Local<Object>::New(iso, g2s1.handle)
4267 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
4271 UniqueId id1 = MakeUniqueId(g1s1.handle);
4272 UniqueId id2 = MakeUniqueId(g2s2.handle);
4273 iso->SetObjectGroupId(g1s1.handle, id1);
4274 iso->SetObjectGroupId(g1s2.handle, id1);
4275 iso->SetReference(g1s1.handle, g1c1.handle);
4276 iso->SetObjectGroupId(g2s1.handle, id2);
4277 iso->SetObjectGroupId(g2s2.handle, id2);
4278 iso->SetReferenceFromGroup(id2, g2c1.handle);
4280 // Do a single full GC, ensure incremental marking is stopped.
4281 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4283 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4285 // All object should be alive.
4286 CHECK_EQ(0, counter.NumberOfWeakCalls());
4289 root.handle.SetWeak(&root, &WeakPointerCallback);
4290 // But make children strong roots---all the objects (except for children)
4291 // should be collectable now.
4292 g1c1.handle.ClearWeak();
4293 g2c1.handle.ClearWeak();
4295 // Groups are deleted, rebuild groups.
4297 UniqueId id1 = MakeUniqueId(g1s1.handle);
4298 UniqueId id2 = MakeUniqueId(g2s2.handle);
4299 iso->SetObjectGroupId(g1s1.handle, id1);
4300 iso->SetObjectGroupId(g1s2.handle, id1);
4301 iso->SetReference(g1s1.handle, g1c1.handle);
4302 iso->SetObjectGroupId(g2s1.handle, id2);
4303 iso->SetObjectGroupId(g2s2.handle, id2);
4304 iso->SetReferenceFromGroup(id2, g2c1.handle);
4307 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4309 // All objects should be gone. 5 global handles in total.
4310 CHECK_EQ(5, counter.NumberOfWeakCalls());
4312 // And now make children weak again and collect them.
4313 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4314 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4316 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4317 CHECK_EQ(7, counter.NumberOfWeakCalls());
4321 THREADED_TEST(ApiObjectGroupsCycle) {
4323 v8::Isolate* iso = env->GetIsolate();
4324 HandleScope scope(iso);
4326 WeakCallCounter counter(1234);
4328 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4329 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4330 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4331 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4332 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4333 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4334 WeakCallCounterAndPersistent<Value> g4s1(&counter);
4335 WeakCallCounterAndPersistent<Value> g4s2(&counter);
4338 HandleScope scope(iso);
4339 g1s1.handle.Reset(iso, Object::New(iso));
4340 g1s2.handle.Reset(iso, Object::New(iso));
4341 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4342 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4343 CHECK(g1s1.handle.IsWeak());
4344 CHECK(g1s2.handle.IsWeak());
4346 g2s1.handle.Reset(iso, Object::New(iso));
4347 g2s2.handle.Reset(iso, Object::New(iso));
4348 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4349 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4350 CHECK(g2s1.handle.IsWeak());
4351 CHECK(g2s2.handle.IsWeak());
4353 g3s1.handle.Reset(iso, Object::New(iso));
4354 g3s2.handle.Reset(iso, Object::New(iso));
4355 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4356 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4357 CHECK(g3s1.handle.IsWeak());
4358 CHECK(g3s2.handle.IsWeak());
4360 g4s1.handle.Reset(iso, Object::New(iso));
4361 g4s2.handle.Reset(iso, Object::New(iso));
4362 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
4363 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
4364 CHECK(g4s1.handle.IsWeak());
4365 CHECK(g4s2.handle.IsWeak());
4368 WeakCallCounterAndPersistent<Value> root(&counter);
4369 root.handle.Reset(iso, g1s1.handle); // make a root.
4371 // Connect groups. We're building the following cycle:
4372 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4375 UniqueId id1 = MakeUniqueId(g1s1.handle);
4376 UniqueId id2 = MakeUniqueId(g2s1.handle);
4377 UniqueId id3 = MakeUniqueId(g3s1.handle);
4378 UniqueId id4 = MakeUniqueId(g4s1.handle);
4379 iso->SetObjectGroupId(g1s1.handle, id1);
4380 iso->SetObjectGroupId(g1s2.handle, id1);
4381 iso->SetReferenceFromGroup(id1, g2s1.handle);
4382 iso->SetObjectGroupId(g2s1.handle, id2);
4383 iso->SetObjectGroupId(g2s2.handle, id2);
4384 iso->SetReferenceFromGroup(id2, g3s1.handle);
4385 iso->SetObjectGroupId(g3s1.handle, id3);
4386 iso->SetObjectGroupId(g3s2.handle, id3);
4387 iso->SetReferenceFromGroup(id3, g4s1.handle);
4388 iso->SetObjectGroupId(g4s1.handle, id4);
4389 iso->SetObjectGroupId(g4s2.handle, id4);
4390 iso->SetReferenceFromGroup(id4, g1s1.handle);
4392 // Do a single full GC
4393 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4395 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4397 // All object should be alive.
4398 CHECK_EQ(0, counter.NumberOfWeakCalls());
4401 root.handle.SetWeak(&root, &WeakPointerCallback);
4403 // Groups are deleted, rebuild groups.
4405 UniqueId id1 = MakeUniqueId(g1s1.handle);
4406 UniqueId id2 = MakeUniqueId(g2s1.handle);
4407 UniqueId id3 = MakeUniqueId(g3s1.handle);
4408 UniqueId id4 = MakeUniqueId(g4s1.handle);
4409 iso->SetObjectGroupId(g1s1.handle, id1);
4410 iso->SetObjectGroupId(g1s2.handle, id1);
4411 iso->SetReferenceFromGroup(id1, g2s1.handle);
4412 iso->SetObjectGroupId(g2s1.handle, id2);
4413 iso->SetObjectGroupId(g2s2.handle, id2);
4414 iso->SetReferenceFromGroup(id2, g3s1.handle);
4415 iso->SetObjectGroupId(g3s1.handle, id3);
4416 iso->SetObjectGroupId(g3s2.handle, id3);
4417 iso->SetReferenceFromGroup(id3, g4s1.handle);
4418 iso->SetObjectGroupId(g4s1.handle, id4);
4419 iso->SetObjectGroupId(g4s2.handle, id4);
4420 iso->SetReferenceFromGroup(id4, g1s1.handle);
4423 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4425 // All objects should be gone. 9 global handles in total.
4426 CHECK_EQ(9, counter.NumberOfWeakCalls());
4430 THREADED_TEST(WeakRootsSurviveTwoRoundsOfGC) {
4432 v8::Isolate* iso = env->GetIsolate();
4433 HandleScope scope(iso);
4435 WeakCallCounter counter(1234);
4437 WeakCallCounterAndPersistent<Value> weak_obj(&counter);
4439 // Create a weak object that references a internalized string.
4441 HandleScope scope(iso);
4442 weak_obj.handle.Reset(iso, Object::New(iso));
4443 weak_obj.handle.SetWeak(&weak_obj, &WeakPointerCallback);
4444 CHECK(weak_obj.handle.IsWeak());
4445 Local<Object>::New(iso, weak_obj.handle.As<Object>())->Set(
4447 String::NewFromUtf8(iso, "magic cookie", String::kInternalizedString));
4449 // Do a single full GC
4450 i::Isolate* i_iso = reinterpret_cast<v8::internal::Isolate*>(iso);
4451 i::Heap* heap = i_iso->heap();
4452 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4454 // We should have received the weak callback.
4455 CHECK_EQ(1, counter.NumberOfWeakCalls());
4457 // Check that the string is still alive.
4459 HandleScope scope(iso);
4460 i::MaybeHandle<i::String> magic_string =
4461 i::StringTable::LookupStringIfExists(
4463 v8::Utils::OpenHandle(*String::NewFromUtf8(iso, "magic cookie")));
4464 magic_string.Check();
4469 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4470 // on the buildbots, so was made non-threaded for the time being.
4471 TEST(ApiObjectGroupsCycleForScavenger) {
4472 i::FLAG_stress_compaction = false;
4473 i::FLAG_gc_global = false;
4475 v8::Isolate* iso = env->GetIsolate();
4476 HandleScope scope(iso);
4478 WeakCallCounter counter(1234);
4480 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4481 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4482 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4483 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4484 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4485 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4488 HandleScope scope(iso);
4489 g1s1.handle.Reset(iso, Object::New(iso));
4490 g1s2.handle.Reset(iso, Object::New(iso));
4491 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4492 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4494 g2s1.handle.Reset(iso, Object::New(iso));
4495 g2s2.handle.Reset(iso, Object::New(iso));
4496 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4497 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4499 g3s1.handle.Reset(iso, Object::New(iso));
4500 g3s2.handle.Reset(iso, Object::New(iso));
4501 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4502 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4506 WeakCallCounterAndPersistent<Value> root(&counter);
4507 root.handle.Reset(iso, g1s1.handle);
4508 root.handle.MarkPartiallyDependent();
4510 // Connect groups. We're building the following cycle:
4511 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4514 HandleScope handle_scope(iso);
4515 g1s1.handle.MarkPartiallyDependent();
4516 g1s2.handle.MarkPartiallyDependent();
4517 g2s1.handle.MarkPartiallyDependent();
4518 g2s2.handle.MarkPartiallyDependent();
4519 g3s1.handle.MarkPartiallyDependent();
4520 g3s2.handle.MarkPartiallyDependent();
4521 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4522 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4523 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4524 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4525 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4526 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4527 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4528 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4529 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4530 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4531 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4532 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4535 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4537 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4539 // All objects should be alive.
4540 CHECK_EQ(0, counter.NumberOfWeakCalls());
4543 root.handle.SetWeak(&root, &WeakPointerCallback);
4544 root.handle.MarkPartiallyDependent();
4546 // Groups are deleted, rebuild groups.
4548 HandleScope handle_scope(iso);
4549 g1s1.handle.MarkPartiallyDependent();
4550 g1s2.handle.MarkPartiallyDependent();
4551 g2s1.handle.MarkPartiallyDependent();
4552 g2s2.handle.MarkPartiallyDependent();
4553 g3s1.handle.MarkPartiallyDependent();
4554 g3s2.handle.MarkPartiallyDependent();
4555 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4556 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4557 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4558 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4559 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4560 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4561 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4562 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4563 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4564 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4565 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4566 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4569 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4571 // All objects should be gone. 7 global handles in total.
4572 CHECK_EQ(7, counter.NumberOfWeakCalls());
4576 THREADED_TEST(ScriptException) {
4578 v8::HandleScope scope(env->GetIsolate());
4579 Local<Script> script = v8_compile("throw 'panama!';");
4580 v8::TryCatch try_catch;
4581 Local<Value> result = script->Run();
4582 CHECK(result.IsEmpty());
4583 CHECK(try_catch.HasCaught());
4584 String::Utf8Value exception_value(try_catch.Exception());
4585 CHECK_EQ(*exception_value, "panama!");
4589 TEST(TryCatchCustomException) {
4591 v8::Isolate* isolate = env->GetIsolate();
4592 v8::HandleScope scope(isolate);
4593 v8::TryCatch try_catch;
4594 CompileRun("function CustomError() { this.a = 'b'; }"
4595 "(function f() { throw new CustomError(); })();");
4596 CHECK(try_catch.HasCaught());
4597 CHECK(try_catch.Exception()->ToObject(isolate)->Get(v8_str("a"))->Equals(
4602 bool message_received;
4605 static void check_message_0(v8::Handle<v8::Message> message,
4606 v8::Handle<Value> data) {
4607 CHECK_EQ(5.76, data->NumberValue());
4608 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4609 CHECK(!message->IsSharedCrossOrigin());
4610 message_received = true;
4614 THREADED_TEST(MessageHandler0) {
4615 message_received = false;
4616 v8::HandleScope scope(CcTest::isolate());
4617 CHECK(!message_received);
4618 LocalContext context;
4619 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4620 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4622 CHECK(message_received);
4623 // clear out the message listener
4624 v8::V8::RemoveMessageListeners(check_message_0);
4628 static void check_message_1(v8::Handle<v8::Message> message,
4629 v8::Handle<Value> data) {
4630 CHECK(data->IsNumber());
4631 CHECK_EQ(1337, data->Int32Value());
4632 CHECK(!message->IsSharedCrossOrigin());
4633 message_received = true;
4637 TEST(MessageHandler1) {
4638 message_received = false;
4639 v8::HandleScope scope(CcTest::isolate());
4640 CHECK(!message_received);
4641 v8::V8::AddMessageListener(check_message_1);
4642 LocalContext context;
4643 CompileRun("throw 1337;");
4644 CHECK(message_received);
4645 // clear out the message listener
4646 v8::V8::RemoveMessageListeners(check_message_1);
4650 static void check_message_2(v8::Handle<v8::Message> message,
4651 v8::Handle<Value> data) {
4652 LocalContext context;
4653 CHECK(data->IsObject());
4654 v8::Local<v8::Value> hidden_property =
4655 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4656 CHECK(v8_str("hidden value")->Equals(hidden_property));
4657 CHECK(!message->IsSharedCrossOrigin());
4658 message_received = true;
4662 TEST(MessageHandler2) {
4663 message_received = false;
4664 v8::HandleScope scope(CcTest::isolate());
4665 CHECK(!message_received);
4666 v8::V8::AddMessageListener(check_message_2);
4667 LocalContext context;
4668 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4669 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4670 v8_str("hidden value"));
4671 context->Global()->Set(v8_str("error"), error);
4672 CompileRun("throw error;");
4673 CHECK(message_received);
4674 // clear out the message listener
4675 v8::V8::RemoveMessageListeners(check_message_2);
4679 static void check_message_3(v8::Handle<v8::Message> message,
4680 v8::Handle<Value> data) {
4681 CHECK(message->IsSharedCrossOrigin());
4682 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4683 message_received = true;
4687 TEST(MessageHandler3) {
4688 message_received = false;
4689 v8::Isolate* isolate = CcTest::isolate();
4690 v8::HandleScope scope(isolate);
4691 CHECK(!message_received);
4692 v8::V8::AddMessageListener(check_message_3);
4693 LocalContext context;
4694 v8::ScriptOrigin origin =
4695 v8::ScriptOrigin(v8_str("6.75"),
4696 v8::Integer::New(isolate, 1),
4697 v8::Integer::New(isolate, 2),
4699 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4702 CHECK(message_received);
4703 // clear out the message listener
4704 v8::V8::RemoveMessageListeners(check_message_3);
4708 static void check_message_4(v8::Handle<v8::Message> message,
4709 v8::Handle<Value> data) {
4710 CHECK(!message->IsSharedCrossOrigin());
4711 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4712 message_received = true;
4716 TEST(MessageHandler4) {
4717 message_received = false;
4718 v8::Isolate* isolate = CcTest::isolate();
4719 v8::HandleScope scope(isolate);
4720 CHECK(!message_received);
4721 v8::V8::AddMessageListener(check_message_4);
4722 LocalContext context;
4723 v8::ScriptOrigin origin =
4724 v8::ScriptOrigin(v8_str("6.75"),
4725 v8::Integer::New(isolate, 1),
4726 v8::Integer::New(isolate, 2),
4727 v8::False(isolate));
4728 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4731 CHECK(message_received);
4732 // clear out the message listener
4733 v8::V8::RemoveMessageListeners(check_message_4);
4737 static void check_message_5a(v8::Handle<v8::Message> message,
4738 v8::Handle<Value> data) {
4739 CHECK(message->IsSharedCrossOrigin());
4740 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4741 message_received = true;
4745 static void check_message_5b(v8::Handle<v8::Message> message,
4746 v8::Handle<Value> data) {
4747 CHECK(!message->IsSharedCrossOrigin());
4748 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4749 message_received = true;
4753 TEST(MessageHandler5) {
4754 message_received = false;
4755 v8::Isolate* isolate = CcTest::isolate();
4756 v8::HandleScope scope(isolate);
4757 CHECK(!message_received);
4758 v8::V8::AddMessageListener(check_message_5a);
4759 LocalContext context;
4760 v8::ScriptOrigin origin =
4761 v8::ScriptOrigin(v8_str("6.75"),
4762 v8::Integer::New(isolate, 1),
4763 v8::Integer::New(isolate, 2),
4765 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4768 CHECK(message_received);
4769 // clear out the message listener
4770 v8::V8::RemoveMessageListeners(check_message_5a);
4772 message_received = false;
4773 v8::V8::AddMessageListener(check_message_5b);
4775 v8::ScriptOrigin(v8_str("6.75"),
4776 v8::Integer::New(isolate, 1),
4777 v8::Integer::New(isolate, 2),
4778 v8::False(isolate));
4779 script = Script::Compile(v8_str("throw 'error'"),
4782 CHECK(message_received);
4783 // clear out the message listener
4784 v8::V8::RemoveMessageListeners(check_message_5b);
4788 THREADED_TEST(GetSetProperty) {
4789 LocalContext context;
4790 v8::Isolate* isolate = context->GetIsolate();
4791 v8::HandleScope scope(isolate);
4792 context->Global()->Set(v8_str("foo"), v8_num(14));
4793 context->Global()->Set(v8_str("12"), v8_num(92));
4794 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4795 context->Global()->Set(v8_num(13), v8_num(56));
4796 Local<Value> foo = CompileRun("this.foo");
4797 CHECK_EQ(14, foo->Int32Value());
4798 Local<Value> twelve = CompileRun("this[12]");
4799 CHECK_EQ(92, twelve->Int32Value());
4800 Local<Value> sixteen = CompileRun("this[16]");
4801 CHECK_EQ(32, sixteen->Int32Value());
4802 Local<Value> thirteen = CompileRun("this[13]");
4803 CHECK_EQ(56, thirteen->Int32Value());
4805 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4806 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4807 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4809 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4810 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4811 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4813 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4814 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4815 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4819 THREADED_TEST(PropertyAttributes) {
4820 LocalContext context;
4821 v8::HandleScope scope(context->GetIsolate());
4823 Local<String> prop = v8_str("none");
4824 context->Global()->Set(prop, v8_num(7));
4825 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4827 prop = v8_str("read_only");
4828 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4829 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4830 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4831 CompileRun("read_only = 9");
4832 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4833 context->Global()->Set(prop, v8_num(10));
4834 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4836 prop = v8_str("dont_delete");
4837 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4838 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4839 CompileRun("delete dont_delete");
4840 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4841 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4843 prop = v8_str("dont_enum");
4844 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4845 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4847 prop = v8_str("absent");
4848 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4849 Local<Value> fake_prop = v8_num(1);
4850 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4853 Local<Value> exception =
4854 CompileRun("({ toString: function() { throw 'exception';} })");
4855 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4856 CHECK(try_catch.HasCaught());
4857 String::Utf8Value exception_value(try_catch.Exception());
4858 CHECK_EQ("exception", *exception_value);
4863 THREADED_TEST(Array) {
4864 LocalContext context;
4865 v8::HandleScope scope(context->GetIsolate());
4866 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4867 CHECK_EQ(0, array->Length());
4868 CHECK(array->Get(0)->IsUndefined());
4869 CHECK(!array->Has(0));
4870 CHECK(array->Get(100)->IsUndefined());
4871 CHECK(!array->Has(100));
4872 array->Set(2, v8_num(7));
4873 CHECK_EQ(3, array->Length());
4874 CHECK(!array->Has(0));
4875 CHECK(!array->Has(1));
4876 CHECK(array->Has(2));
4877 CHECK_EQ(7, array->Get(2)->Int32Value());
4878 Local<Value> obj = CompileRun("[1, 2, 3]");
4879 Local<v8::Array> arr = obj.As<v8::Array>();
4880 CHECK_EQ(3, arr->Length());
4881 CHECK_EQ(1, arr->Get(0)->Int32Value());
4882 CHECK_EQ(2, arr->Get(1)->Int32Value());
4883 CHECK_EQ(3, arr->Get(2)->Int32Value());
4884 array = v8::Array::New(context->GetIsolate(), 27);
4885 CHECK_EQ(27, array->Length());
4886 array = v8::Array::New(context->GetIsolate(), -27);
4887 CHECK_EQ(0, array->Length());
4891 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4892 v8::EscapableHandleScope scope(args.GetIsolate());
4893 ApiTestFuzzer::Fuzz();
4894 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4895 for (int i = 0; i < args.Length(); i++)
4896 result->Set(i, args[i]);
4897 args.GetReturnValue().Set(scope.Escape(result));
4901 THREADED_TEST(Vector) {
4902 v8::Isolate* isolate = CcTest::isolate();
4903 v8::HandleScope scope(isolate);
4904 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4905 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4906 LocalContext context(0, global);
4908 const char* fun = "f()";
4909 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4910 CHECK_EQ(0, a0->Length());
4912 const char* fun2 = "f(11)";
4913 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4914 CHECK_EQ(1, a1->Length());
4915 CHECK_EQ(11, a1->Get(0)->Int32Value());
4917 const char* fun3 = "f(12, 13)";
4918 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4919 CHECK_EQ(2, a2->Length());
4920 CHECK_EQ(12, a2->Get(0)->Int32Value());
4921 CHECK_EQ(13, a2->Get(1)->Int32Value());
4923 const char* fun4 = "f(14, 15, 16)";
4924 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4925 CHECK_EQ(3, a3->Length());
4926 CHECK_EQ(14, a3->Get(0)->Int32Value());
4927 CHECK_EQ(15, a3->Get(1)->Int32Value());
4928 CHECK_EQ(16, a3->Get(2)->Int32Value());
4930 const char* fun5 = "f(17, 18, 19, 20)";
4931 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4932 CHECK_EQ(4, a4->Length());
4933 CHECK_EQ(17, a4->Get(0)->Int32Value());
4934 CHECK_EQ(18, a4->Get(1)->Int32Value());
4935 CHECK_EQ(19, a4->Get(2)->Int32Value());
4936 CHECK_EQ(20, a4->Get(3)->Int32Value());
4940 THREADED_TEST(FunctionCall) {
4941 LocalContext context;
4942 v8::Isolate* isolate = context->GetIsolate();
4943 v8::HandleScope scope(isolate);
4947 " for (var i = 0; i < arguments.length; i++) {"
4948 " result.push(arguments[i]);"
4952 "function ReturnThisSloppy() {"
4955 "function ReturnThisStrict() {"
4959 Local<Function> Foo =
4960 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4961 Local<Function> ReturnThisSloppy =
4962 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4963 Local<Function> ReturnThisStrict =
4964 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4966 v8::Handle<Value>* args0 = NULL;
4967 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4968 CHECK_EQ(0, a0->Length());
4970 v8::Handle<Value> args1[] = { v8_num(1.1) };
4971 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4972 CHECK_EQ(1, a1->Length());
4973 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4975 v8::Handle<Value> args2[] = { v8_num(2.2),
4977 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4978 CHECK_EQ(2, a2->Length());
4979 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4980 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4982 v8::Handle<Value> args3[] = { v8_num(4.4),
4985 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4986 CHECK_EQ(3, a3->Length());
4987 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4988 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4989 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4991 v8::Handle<Value> args4[] = { v8_num(7.7),
4995 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4996 CHECK_EQ(4, a4->Length());
4997 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4998 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4999 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
5000 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
5002 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
5003 CHECK(r1->StrictEquals(context->Global()));
5004 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
5005 CHECK(r2->StrictEquals(context->Global()));
5006 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
5007 CHECK(r3->IsNumberObject());
5008 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
5009 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
5010 CHECK(r4->IsStringObject());
5011 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
5012 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
5013 CHECK(r5->IsBooleanObject());
5014 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
5016 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
5017 CHECK(r6->IsUndefined());
5018 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
5019 CHECK(r7->IsNull());
5020 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
5021 CHECK(r8->StrictEquals(v8_num(42)));
5022 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
5023 CHECK(r9->StrictEquals(v8_str("hello")));
5024 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
5025 CHECK(r10->StrictEquals(v8::True(isolate)));
5029 THREADED_TEST(ConstructCall) {
5030 LocalContext context;
5031 v8::Isolate* isolate = context->GetIsolate();
5032 v8::HandleScope scope(isolate);
5036 " for (var i = 0; i < arguments.length; i++) {"
5037 " result.push(arguments[i]);"
5041 Local<Function> Foo =
5042 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
5044 v8::Handle<Value>* args0 = NULL;
5045 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
5046 CHECK_EQ(0, a0->Length());
5048 v8::Handle<Value> args1[] = { v8_num(1.1) };
5049 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
5050 CHECK_EQ(1, a1->Length());
5051 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
5053 v8::Handle<Value> args2[] = { v8_num(2.2),
5055 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
5056 CHECK_EQ(2, a2->Length());
5057 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
5058 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
5060 v8::Handle<Value> args3[] = { v8_num(4.4),
5063 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
5064 CHECK_EQ(3, a3->Length());
5065 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
5066 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
5067 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
5069 v8::Handle<Value> args4[] = { v8_num(7.7),
5073 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
5074 CHECK_EQ(4, a4->Length());
5075 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
5076 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
5077 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
5078 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
5082 static void CheckUncle(v8::TryCatch* try_catch) {
5083 CHECK(try_catch->HasCaught());
5084 String::Utf8Value str_value(try_catch->Exception());
5085 CHECK_EQ(*str_value, "uncle?");
5090 THREADED_TEST(ConversionNumber) {
5092 v8::Isolate* isolate = env->GetIsolate();
5093 v8::HandleScope scope(isolate);
5094 // Very large number.
5095 CompileRun("var obj = Math.pow(2,32) * 1237;");
5096 Local<Value> obj = env->Global()->Get(v8_str("obj"));
5097 CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
5098 CHECK_EQ(0, obj->ToInt32(isolate)->Value());
5100 obj->ToUint32(isolate)->Value()); // NOLINT - no CHECK_EQ for unsigned.
5102 CompileRun("var obj = -1234567890123;");
5103 obj = env->Global()->Get(v8_str("obj"));
5104 CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
5105 CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
5106 CHECK(2382691125u == obj->ToUint32(isolate)->Value()); // NOLINT
5107 // Small positive integer.
5108 CompileRun("var obj = 42;");
5109 obj = env->Global()->Get(v8_str("obj"));
5110 CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
5111 CHECK_EQ(42, obj->ToInt32(isolate)->Value());
5112 CHECK(42u == obj->ToUint32(isolate)->Value()); // NOLINT
5113 // Negative integer.
5114 CompileRun("var obj = -37;");
5115 obj = env->Global()->Get(v8_str("obj"));
5116 CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
5117 CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
5118 CHECK(4294967259u == obj->ToUint32(isolate)->Value()); // NOLINT
5119 // Positive non-int32 integer.
5120 CompileRun("var obj = 0x81234567;");
5121 obj = env->Global()->Get(v8_str("obj"));
5122 CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
5123 CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
5124 CHECK(2166572391u == obj->ToUint32(isolate)->Value()); // NOLINT
5126 CompileRun("var obj = 42.3;");
5127 obj = env->Global()->Get(v8_str("obj"));
5128 CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
5129 CHECK_EQ(42, obj->ToInt32(isolate)->Value());
5130 CHECK(42u == obj->ToUint32(isolate)->Value()); // NOLINT
5131 // Large negative fraction.
5132 CompileRun("var obj = -5726623061.75;");
5133 obj = env->Global()->Get(v8_str("obj"));
5134 CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
5135 CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
5136 CHECK(2863311531u == obj->ToUint32(isolate)->Value()); // NOLINT
5140 THREADED_TEST(isNumberType) {
5142 v8::HandleScope scope(env->GetIsolate());
5143 // Very large number.
5144 CompileRun("var obj = Math.pow(2,32) * 1237;");
5145 Local<Value> obj = env->Global()->Get(v8_str("obj"));
5146 CHECK(!obj->IsInt32());
5147 CHECK(!obj->IsUint32());
5148 // Large negative number.
5149 CompileRun("var obj = -1234567890123;");
5150 obj = env->Global()->Get(v8_str("obj"));
5151 CHECK(!obj->IsInt32());
5152 CHECK(!obj->IsUint32());
5153 // Small positive integer.
5154 CompileRun("var obj = 42;");
5155 obj = env->Global()->Get(v8_str("obj"));
5156 CHECK(obj->IsInt32());
5157 CHECK(obj->IsUint32());
5158 // Negative integer.
5159 CompileRun("var obj = -37;");
5160 obj = env->Global()->Get(v8_str("obj"));
5161 CHECK(obj->IsInt32());
5162 CHECK(!obj->IsUint32());
5163 // Positive non-int32 integer.
5164 CompileRun("var obj = 0x81234567;");
5165 obj = env->Global()->Get(v8_str("obj"));
5166 CHECK(!obj->IsInt32());
5167 CHECK(obj->IsUint32());
5169 CompileRun("var obj = 42.3;");
5170 obj = env->Global()->Get(v8_str("obj"));
5171 CHECK(!obj->IsInt32());
5172 CHECK(!obj->IsUint32());
5173 // Large negative fraction.
5174 CompileRun("var obj = -5726623061.75;");
5175 obj = env->Global()->Get(v8_str("obj"));
5176 CHECK(!obj->IsInt32());
5177 CHECK(!obj->IsUint32());
5179 CompileRun("var obj = 0.0;");
5180 obj = env->Global()->Get(v8_str("obj"));
5181 CHECK(obj->IsInt32());
5182 CHECK(obj->IsUint32());
5184 CompileRun("var obj = -0.0;");
5185 obj = env->Global()->Get(v8_str("obj"));
5186 CHECK(!obj->IsInt32());
5187 CHECK(!obj->IsUint32());
5191 THREADED_TEST(ConversionException) {
5193 v8::Isolate* isolate = env->GetIsolate();
5194 v8::HandleScope scope(isolate);
5196 "function TestClass() { };"
5197 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
5198 "var obj = new TestClass();");
5199 Local<Value> obj = env->Global()->Get(v8_str("obj"));
5201 v8::TryCatch try_catch(isolate);
5203 Local<Value> to_string_result = obj->ToString(isolate);
5204 CHECK(to_string_result.IsEmpty());
5205 CheckUncle(&try_catch);
5207 Local<Value> to_number_result = obj->ToNumber(isolate);
5208 CHECK(to_number_result.IsEmpty());
5209 CheckUncle(&try_catch);
5211 Local<Value> to_integer_result = obj->ToInteger(isolate);
5212 CHECK(to_integer_result.IsEmpty());
5213 CheckUncle(&try_catch);
5215 Local<Value> to_uint32_result = obj->ToUint32(isolate);
5216 CHECK(to_uint32_result.IsEmpty());
5217 CheckUncle(&try_catch);
5219 Local<Value> to_int32_result = obj->ToInt32(isolate);
5220 CHECK(to_int32_result.IsEmpty());
5221 CheckUncle(&try_catch);
5223 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
5224 CHECK(to_object_result.IsEmpty());
5225 CHECK(try_catch.HasCaught());
5228 int32_t int32_value = obj->Int32Value();
5229 CHECK_EQ(0, int32_value);
5230 CheckUncle(&try_catch);
5232 uint32_t uint32_value = obj->Uint32Value();
5233 CHECK_EQ(0, uint32_value);
5234 CheckUncle(&try_catch);
5236 double number_value = obj->NumberValue();
5237 CHECK_NE(0, std::isnan(number_value));
5238 CheckUncle(&try_catch);
5240 int64_t integer_value = obj->IntegerValue();
5241 CHECK_EQ(0.0, static_cast<double>(integer_value));
5242 CheckUncle(&try_catch);
5246 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
5247 ApiTestFuzzer::Fuzz();
5248 args.GetIsolate()->ThrowException(v8_str("konto"));
5252 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5253 if (args.Length() < 1) {
5254 args.GetReturnValue().Set(false);
5257 v8::HandleScope scope(args.GetIsolate());
5258 v8::TryCatch try_catch;
5259 Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
5260 CHECK(!try_catch.HasCaught() || result.IsEmpty());
5261 args.GetReturnValue().Set(try_catch.HasCaught());
5265 THREADED_TEST(APICatch) {
5266 v8::Isolate* isolate = CcTest::isolate();
5267 v8::HandleScope scope(isolate);
5268 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5269 templ->Set(v8_str("ThrowFromC"),
5270 v8::FunctionTemplate::New(isolate, ThrowFromC));
5271 LocalContext context(0, templ);
5273 "var thrown = false;"
5279 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
5280 CHECK(thrown->BooleanValue());
5284 THREADED_TEST(APIThrowTryCatch) {
5285 v8::Isolate* isolate = CcTest::isolate();
5286 v8::HandleScope scope(isolate);
5287 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5288 templ->Set(v8_str("ThrowFromC"),
5289 v8::FunctionTemplate::New(isolate, ThrowFromC));
5290 LocalContext context(0, templ);
5291 v8::TryCatch try_catch;
5292 CompileRun("ThrowFromC();");
5293 CHECK(try_catch.HasCaught());
5297 // Test that a try-finally block doesn't shadow a try-catch block
5298 // when setting up an external handler.
5300 // BUG(271): Some of the exception propagation does not work on the
5301 // ARM simulator because the simulator separates the C++ stack and the
5302 // JS stack. This test therefore fails on the simulator. The test is
5303 // not threaded to allow the threading tests to run on the simulator.
5304 TEST(TryCatchInTryFinally) {
5305 v8::Isolate* isolate = CcTest::isolate();
5306 v8::HandleScope scope(isolate);
5307 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5308 templ->Set(v8_str("CCatcher"),
5309 v8::FunctionTemplate::New(isolate, CCatcher));
5310 LocalContext context(0, templ);
5311 Local<Value> result = CompileRun("try {"
5313 " CCatcher('throw 7;');"
5318 CHECK(result->IsTrue());
5322 static void check_reference_error_message(
5323 v8::Handle<v8::Message> message,
5324 v8::Handle<v8::Value> data) {
5325 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
5326 CHECK(message->Get()->Equals(v8_str(reference_error)));
5330 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
5331 ApiTestFuzzer::Fuzz();
5336 // Test that overwritten methods are not invoked on uncaught exception
5337 // formatting. However, they are invoked when performing normal error
5338 // string conversions.
5339 TEST(APIThrowMessageOverwrittenToString) {
5340 v8::Isolate* isolate = CcTest::isolate();
5341 v8::HandleScope scope(isolate);
5342 v8::V8::AddMessageListener(check_reference_error_message);
5343 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5344 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
5345 LocalContext context(NULL, templ);
5346 CompileRun("asdf;");
5347 CompileRun("var limit = {};"
5348 "limit.valueOf = fail;"
5349 "Error.stackTraceLimit = limit;");
5351 CompileRun("Array.prototype.pop = fail;");
5352 CompileRun("Object.prototype.hasOwnProperty = fail;");
5353 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
5354 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
5355 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
5356 CompileRun("ReferenceError.prototype.toString ="
5357 " function() { return 'Whoops' }");
5358 CompileRun("asdf;");
5359 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
5360 CompileRun("asdf;");
5361 CompileRun("ReferenceError.prototype.constructor = void 0;");
5362 CompileRun("asdf;");
5363 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
5364 CompileRun("asdf;");
5365 CompileRun("ReferenceError.prototype = new Object();");
5366 CompileRun("asdf;");
5367 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
5368 CHECK(string->Equals(v8_str("Whoops")));
5369 CompileRun("ReferenceError.prototype.constructor = new Object();"
5370 "ReferenceError.prototype.constructor.name = 1;"
5371 "Number.prototype.toString = function() { return 'Whoops'; };"
5372 "ReferenceError.prototype.toString = Object.prototype.toString;");
5373 CompileRun("asdf;");
5374 v8::V8::RemoveMessageListeners(check_reference_error_message);
5378 static void check_custom_error_tostring(
5379 v8::Handle<v8::Message> message,
5380 v8::Handle<v8::Value> data) {
5381 const char* uncaught_error = "Uncaught MyError toString";
5382 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5386 TEST(CustomErrorToString) {
5387 LocalContext context;
5388 v8::HandleScope scope(context->GetIsolate());
5389 v8::V8::AddMessageListener(check_custom_error_tostring);
5391 "function MyError(name, message) { "
5392 " this.name = name; "
5393 " this.message = message; "
5395 "MyError.prototype = Object.create(Error.prototype); "
5396 "MyError.prototype.toString = function() { "
5397 " return 'MyError toString'; "
5399 "throw new MyError('my name', 'my message'); ");
5400 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
5404 static void check_custom_error_message(
5405 v8::Handle<v8::Message> message,
5406 v8::Handle<v8::Value> data) {
5407 const char* uncaught_error = "Uncaught MyError: my message";
5408 printf("%s\n", *v8::String::Utf8Value(message->Get()));
5409 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5413 TEST(CustomErrorMessage) {
5414 LocalContext context;
5415 v8::HandleScope scope(context->GetIsolate());
5416 v8::V8::AddMessageListener(check_custom_error_message);
5420 "function MyError(msg) { "
5421 " this.name = 'MyError'; "
5422 " this.message = msg; "
5424 "MyError.prototype = new Error(); "
5425 "throw new MyError('my message'); ");
5429 "function MyError(msg) { "
5430 " this.name = 'MyError'; "
5431 " this.message = msg; "
5433 "inherits = function(childCtor, parentCtor) { "
5434 " function tempCtor() {}; "
5435 " tempCtor.prototype = parentCtor.prototype; "
5436 " childCtor.superClass_ = parentCtor.prototype; "
5437 " childCtor.prototype = new tempCtor(); "
5438 " childCtor.prototype.constructor = childCtor; "
5440 "inherits(MyError, Error); "
5441 "throw new MyError('my message'); ");
5445 "function MyError(msg) { "
5446 " this.name = 'MyError'; "
5447 " this.message = msg; "
5449 "MyError.prototype = Object.create(Error.prototype); "
5450 "throw new MyError('my message'); ");
5452 v8::V8::RemoveMessageListeners(check_custom_error_message);
5456 static void receive_message(v8::Handle<v8::Message> message,
5457 v8::Handle<v8::Value> data) {
5459 message_received = true;
5463 TEST(APIThrowMessage) {
5464 message_received = false;
5465 v8::Isolate* isolate = CcTest::isolate();
5466 v8::HandleScope scope(isolate);
5467 v8::V8::AddMessageListener(receive_message);
5468 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5469 templ->Set(v8_str("ThrowFromC"),
5470 v8::FunctionTemplate::New(isolate, ThrowFromC));
5471 LocalContext context(0, templ);
5472 CompileRun("ThrowFromC();");
5473 CHECK(message_received);
5474 v8::V8::RemoveMessageListeners(receive_message);
5478 TEST(APIThrowMessageAndVerboseTryCatch) {
5479 message_received = false;
5480 v8::Isolate* isolate = CcTest::isolate();
5481 v8::HandleScope scope(isolate);
5482 v8::V8::AddMessageListener(receive_message);
5483 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5484 templ->Set(v8_str("ThrowFromC"),
5485 v8::FunctionTemplate::New(isolate, ThrowFromC));
5486 LocalContext context(0, templ);
5487 v8::TryCatch try_catch;
5488 try_catch.SetVerbose(true);
5489 Local<Value> result = CompileRun("ThrowFromC();");
5490 CHECK(try_catch.HasCaught());
5491 CHECK(result.IsEmpty());
5492 CHECK(message_received);
5493 v8::V8::RemoveMessageListeners(receive_message);
5497 TEST(APIStackOverflowAndVerboseTryCatch) {
5498 message_received = false;
5499 LocalContext context;
5500 v8::HandleScope scope(context->GetIsolate());
5501 v8::V8::AddMessageListener(receive_message);
5502 v8::TryCatch try_catch;
5503 try_catch.SetVerbose(true);
5504 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5505 CHECK(try_catch.HasCaught());
5506 CHECK(result.IsEmpty());
5507 CHECK(message_received);
5508 v8::V8::RemoveMessageListeners(receive_message);
5512 THREADED_TEST(ExternalScriptException) {
5513 v8::Isolate* isolate = CcTest::isolate();
5514 v8::HandleScope scope(isolate);
5515 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5516 templ->Set(v8_str("ThrowFromC"),
5517 v8::FunctionTemplate::New(isolate, ThrowFromC));
5518 LocalContext context(0, templ);
5520 v8::TryCatch try_catch;
5521 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5522 CHECK(result.IsEmpty());
5523 CHECK(try_catch.HasCaught());
5524 String::Utf8Value exception_value(try_catch.Exception());
5525 CHECK_EQ("konto", *exception_value);
5530 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5531 ApiTestFuzzer::Fuzz();
5532 CHECK_EQ(4, args.Length());
5533 int count = args[0]->Int32Value();
5534 int cInterval = args[2]->Int32Value();
5536 args.GetIsolate()->ThrowException(v8_str("FromC"));
5539 Local<v8::Object> global =
5540 args.GetIsolate()->GetCurrentContext()->Global();
5541 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5542 v8::Handle<Value> argv[] = { v8_num(count - 1),
5546 if (count % cInterval == 0) {
5547 v8::TryCatch try_catch;
5548 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5549 int expected = args[3]->Int32Value();
5550 if (try_catch.HasCaught()) {
5551 CHECK_EQ(expected, count);
5552 CHECK(result.IsEmpty());
5553 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5555 CHECK_NE(expected, count);
5557 args.GetReturnValue().Set(result);
5560 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5567 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5568 ApiTestFuzzer::Fuzz();
5569 CHECK_EQ(3, args.Length());
5570 bool equality = args[0]->BooleanValue();
5571 int count = args[1]->Int32Value();
5572 int expected = args[2]->Int32Value();
5574 CHECK_EQ(count, expected);
5576 CHECK_NE(count, expected);
5581 THREADED_TEST(EvalInTryFinally) {
5582 LocalContext context;
5583 v8::HandleScope scope(context->GetIsolate());
5584 v8::TryCatch try_catch;
5585 CompileRun("(function() {"
5587 " eval('asldkf (*&^&*^');"
5592 CHECK(!try_catch.HasCaught());
5596 // This test works by making a stack of alternating JavaScript and C
5597 // activations. These activations set up exception handlers with regular
5598 // intervals, one interval for C activations and another for JavaScript
5599 // activations. When enough activations have been created an exception is
5600 // thrown and we check that the right activation catches the exception and that
5601 // no other activations do. The right activation is always the topmost one with
5602 // a handler, regardless of whether it is in JavaScript or C.
5604 // The notation used to describe a test case looks like this:
5606 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5608 // Each entry is an activation, either JS or C. The index is the count at that
5609 // level. Stars identify activations with exception handlers, the @ identifies
5610 // the exception handler that should catch the exception.
5612 // BUG(271): Some of the exception propagation does not work on the
5613 // ARM simulator because the simulator separates the C++ stack and the
5614 // JS stack. This test therefore fails on the simulator. The test is
5615 // not threaded to allow the threading tests to run on the simulator.
5616 TEST(ExceptionOrder) {
5617 v8::Isolate* isolate = CcTest::isolate();
5618 v8::HandleScope scope(isolate);
5619 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5620 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5621 templ->Set(v8_str("CThrowCountDown"),
5622 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5623 LocalContext context(0, templ);
5625 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5626 " if (count == 0) throw 'FromJS';"
5627 " if (count % jsInterval == 0) {"
5629 " var value = CThrowCountDown(count - 1,"
5633 " check(false, count, expected);"
5636 " check(true, count, expected);"
5639 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5642 Local<Function> fun =
5643 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5646 // count jsInterval cInterval expected
5648 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5649 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5650 fun->Call(fun, argc, a0);
5652 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5653 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5654 fun->Call(fun, argc, a1);
5656 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5657 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5658 fun->Call(fun, argc, a2);
5660 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5661 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5662 fun->Call(fun, argc, a3);
5664 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5665 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5666 fun->Call(fun, argc, a4);
5668 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5669 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5670 fun->Call(fun, argc, a5);
5674 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5675 ApiTestFuzzer::Fuzz();
5676 CHECK_EQ(1, args.Length());
5677 args.GetIsolate()->ThrowException(args[0]);
5681 THREADED_TEST(ThrowValues) {
5682 v8::Isolate* isolate = CcTest::isolate();
5683 v8::HandleScope scope(isolate);
5684 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5685 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5686 LocalContext context(0, templ);
5687 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5688 "function Run(obj) {"
5694 " return 'no exception';"
5696 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5697 CHECK_EQ(5, result->Length());
5698 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5699 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5700 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5701 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5702 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5703 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5704 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5708 THREADED_TEST(CatchZero) {
5709 LocalContext context;
5710 v8::HandleScope scope(context->GetIsolate());
5711 v8::TryCatch try_catch;
5712 CHECK(!try_catch.HasCaught());
5713 CompileRun("throw 10");
5714 CHECK(try_catch.HasCaught());
5715 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5717 CHECK(!try_catch.HasCaught());
5718 CompileRun("throw 0");
5719 CHECK(try_catch.HasCaught());
5720 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5724 THREADED_TEST(CatchExceptionFromWith) {
5725 LocalContext context;
5726 v8::HandleScope scope(context->GetIsolate());
5727 v8::TryCatch try_catch;
5728 CHECK(!try_catch.HasCaught());
5729 CompileRun("var o = {}; with (o) { throw 42; }");
5730 CHECK(try_catch.HasCaught());
5734 THREADED_TEST(TryCatchAndFinallyHidingException) {
5735 LocalContext context;
5736 v8::HandleScope scope(context->GetIsolate());
5737 v8::TryCatch try_catch;
5738 CHECK(!try_catch.HasCaught());
5739 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5740 CompileRun("f({toString: function() { throw 42; }});");
5741 CHECK(!try_catch.HasCaught());
5745 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5746 v8::TryCatch try_catch;
5750 THREADED_TEST(TryCatchAndFinally) {
5751 LocalContext context;
5752 v8::Isolate* isolate = context->GetIsolate();
5753 v8::HandleScope scope(isolate);
5754 context->Global()->Set(
5755 v8_str("native_with_try_catch"),
5756 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5757 v8::TryCatch try_catch;
5758 CHECK(!try_catch.HasCaught());
5761 " throw new Error('a');\n"
5763 " native_with_try_catch();\n"
5765 CHECK(try_catch.HasCaught());
5769 static void TryCatchNested1Helper(int depth) {
5771 v8::TryCatch try_catch;
5772 try_catch.SetVerbose(true);
5773 TryCatchNested1Helper(depth - 1);
5774 CHECK(try_catch.HasCaught());
5775 try_catch.ReThrow();
5777 CcTest::isolate()->ThrowException(v8_str("E1"));
5782 static void TryCatchNested2Helper(int depth) {
5784 v8::TryCatch try_catch;
5785 try_catch.SetVerbose(true);
5786 TryCatchNested2Helper(depth - 1);
5787 CHECK(try_catch.HasCaught());
5788 try_catch.ReThrow();
5790 CompileRun("throw 'E2';");
5795 TEST(TryCatchNested) {
5796 v8::V8::Initialize();
5797 LocalContext context;
5798 v8::HandleScope scope(context->GetIsolate());
5801 // Test nested try-catch with a native throw in the end.
5802 v8::TryCatch try_catch;
5803 TryCatchNested1Helper(5);
5804 CHECK(try_catch.HasCaught());
5805 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5809 // Test nested try-catch with a JavaScript throw in the end.
5810 v8::TryCatch try_catch;
5811 TryCatchNested2Helper(5);
5812 CHECK(try_catch.HasCaught());
5813 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5818 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5819 CHECK(try_catch->HasCaught());
5820 Handle<Message> message = try_catch->Message();
5821 Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5822 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5823 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5824 "Uncaught Error: a"));
5825 CHECK_EQ(1, message->GetLineNumber());
5826 CHECK_EQ(6, message->GetStartColumn());
5830 void TryCatchMixedNestingHelper(
5831 const v8::FunctionCallbackInfo<v8::Value>& args) {
5832 ApiTestFuzzer::Fuzz();
5833 v8::TryCatch try_catch;
5834 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5835 CHECK(try_catch.HasCaught());
5836 TryCatchMixedNestingCheck(&try_catch);
5837 try_catch.ReThrow();
5841 // This test ensures that an outer TryCatch in the following situation:
5842 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5843 // does not clobber the Message object generated for the inner TryCatch.
5844 // This exercises the ability of TryCatch.ReThrow() to restore the
5845 // inner pending Message before throwing the exception again.
5846 TEST(TryCatchMixedNesting) {
5847 v8::Isolate* isolate = CcTest::isolate();
5848 v8::HandleScope scope(isolate);
5849 v8::V8::Initialize();
5850 v8::TryCatch try_catch;
5851 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5852 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5853 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5854 LocalContext context(0, templ);
5855 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5856 TryCatchMixedNestingCheck(&try_catch);
5860 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5861 ApiTestFuzzer::Fuzz();
5862 v8::TryCatch try_catch;
5863 args.GetIsolate()->ThrowException(v8_str("boom"));
5864 CHECK(try_catch.HasCaught());
5868 TEST(TryCatchNative) {
5869 v8::Isolate* isolate = CcTest::isolate();
5870 v8::HandleScope scope(isolate);
5871 v8::V8::Initialize();
5872 v8::TryCatch try_catch;
5873 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5874 templ->Set(v8_str("TryCatchNativeHelper"),
5875 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5876 LocalContext context(0, templ);
5877 CompileRun("TryCatchNativeHelper();");
5878 CHECK(!try_catch.HasCaught());
5882 void TryCatchNativeResetHelper(
5883 const v8::FunctionCallbackInfo<v8::Value>& args) {
5884 ApiTestFuzzer::Fuzz();
5885 v8::TryCatch try_catch;
5886 args.GetIsolate()->ThrowException(v8_str("boom"));
5887 CHECK(try_catch.HasCaught());
5889 CHECK(!try_catch.HasCaught());
5893 TEST(TryCatchNativeReset) {
5894 v8::Isolate* isolate = CcTest::isolate();
5895 v8::HandleScope scope(isolate);
5896 v8::V8::Initialize();
5897 v8::TryCatch try_catch;
5898 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5899 templ->Set(v8_str("TryCatchNativeResetHelper"),
5900 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5901 LocalContext context(0, templ);
5902 CompileRun("TryCatchNativeResetHelper();");
5903 CHECK(!try_catch.HasCaught());
5907 THREADED_TEST(Equality) {
5908 LocalContext context;
5909 v8::Isolate* isolate = context->GetIsolate();
5910 v8::HandleScope scope(context->GetIsolate());
5911 // Check that equality works at all before relying on CHECK_EQ
5912 CHECK(v8_str("a")->Equals(v8_str("a")));
5913 CHECK(!v8_str("a")->Equals(v8_str("b")));
5915 CHECK_EQ(v8_str("a"), v8_str("a"));
5916 CHECK_NE(v8_str("a"), v8_str("b"));
5917 CHECK_EQ(v8_num(1), v8_num(1));
5918 CHECK_EQ(v8_num(1.00), v8_num(1));
5919 CHECK_NE(v8_num(1), v8_num(2));
5921 // Assume String is not internalized.
5922 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5923 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5924 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5925 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5926 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5927 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5928 Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
5929 CHECK(!not_a_number->StrictEquals(not_a_number));
5930 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5931 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5933 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5934 v8::Persistent<v8::Object> alias(isolate, obj);
5935 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5938 CHECK(v8_str("a")->SameValue(v8_str("a")));
5939 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5940 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5941 CHECK(v8_num(1)->SameValue(v8_num(1)));
5942 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5943 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5944 CHECK(not_a_number->SameValue(not_a_number));
5945 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5946 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5950 THREADED_TEST(MultiRun) {
5951 LocalContext context;
5952 v8::HandleScope scope(context->GetIsolate());
5953 Local<Script> script = v8_compile("x");
5954 for (int i = 0; i < 10; i++)
5959 static void GetXValue(Local<String> name,
5960 const v8::PropertyCallbackInfo<v8::Value>& info) {
5961 ApiTestFuzzer::Fuzz();
5962 CHECK_EQ(info.Data(), v8_str("donut"));
5963 CHECK_EQ(name, v8_str("x"));
5964 info.GetReturnValue().Set(name);
5968 THREADED_TEST(SimplePropertyRead) {
5969 LocalContext context;
5970 v8::Isolate* isolate = context->GetIsolate();
5971 v8::HandleScope scope(isolate);
5972 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5973 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5974 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5975 Local<Script> script = v8_compile("obj.x");
5976 for (int i = 0; i < 10; i++) {
5977 Local<Value> result = script->Run();
5978 CHECK_EQ(result, v8_str("x"));
5983 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5984 LocalContext context;
5985 v8::Isolate* isolate = context->GetIsolate();
5986 v8::HandleScope scope(isolate);
5987 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5988 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5989 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5991 // Uses getOwnPropertyDescriptor to check the configurable status
5992 Local<Script> script_desc = v8_compile(
5993 "var prop = Object.getOwnPropertyDescriptor( "
5995 "prop.configurable;");
5996 Local<Value> result = script_desc->Run();
5997 CHECK_EQ(result->BooleanValue(), true);
5999 // Redefine get - but still configurable
6000 Local<Script> script_define = v8_compile(
6001 "var desc = { get: function(){return 42; },"
6002 " configurable: true };"
6003 "Object.defineProperty(obj, 'x', desc);"
6005 result = script_define->Run();
6006 CHECK_EQ(result, v8_num(42));
6008 // Check that the accessor is still configurable
6009 result = script_desc->Run();
6010 CHECK_EQ(result->BooleanValue(), true);
6012 // Redefine to a non-configurable
6013 script_define = v8_compile(
6014 "var desc = { get: function(){return 43; },"
6015 " configurable: false };"
6016 "Object.defineProperty(obj, 'x', desc);"
6018 result = script_define->Run();
6019 CHECK_EQ(result, v8_num(43));
6020 result = script_desc->Run();
6021 CHECK_EQ(result->BooleanValue(), false);
6023 // Make sure that it is not possible to redefine again
6024 v8::TryCatch try_catch;
6025 result = script_define->Run();
6026 CHECK(try_catch.HasCaught());
6027 String::Utf8Value exception_value(try_catch.Exception());
6028 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
6032 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
6033 v8::Isolate* isolate = CcTest::isolate();
6034 v8::HandleScope scope(isolate);
6035 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6036 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
6037 LocalContext context;
6038 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6040 Local<Script> script_desc = v8_compile(
6042 "Object.getOwnPropertyDescriptor( "
6044 "prop.configurable;");
6045 Local<Value> result = script_desc->Run();
6046 CHECK_EQ(result->BooleanValue(), true);
6048 Local<Script> script_define = v8_compile(
6049 "var desc = {get: function(){return 42; },"
6050 " configurable: true };"
6051 "Object.defineProperty(obj, 'x', desc);"
6053 result = script_define->Run();
6054 CHECK_EQ(result, v8_num(42));
6057 result = script_desc->Run();
6058 CHECK_EQ(result->BooleanValue(), true);
6061 script_define = v8_compile(
6062 "var desc = {get: function(){return 43; },"
6063 " configurable: false };"
6064 "Object.defineProperty(obj, 'x', desc);"
6066 result = script_define->Run();
6067 CHECK_EQ(result, v8_num(43));
6068 result = script_desc->Run();
6070 CHECK_EQ(result->BooleanValue(), false);
6072 v8::TryCatch try_catch;
6073 result = script_define->Run();
6074 CHECK(try_catch.HasCaught());
6075 String::Utf8Value exception_value(try_catch.Exception());
6076 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
6080 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
6082 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
6086 THREADED_TEST(DefineAPIAccessorOnObject) {
6087 v8::Isolate* isolate = CcTest::isolate();
6088 v8::HandleScope scope(isolate);
6089 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6090 LocalContext context;
6092 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6093 CompileRun("var obj2 = {};");
6095 CHECK(CompileRun("obj1.x")->IsUndefined());
6096 CHECK(CompileRun("obj2.x")->IsUndefined());
6098 CHECK(GetGlobalProperty(&context, "obj1")->
6099 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6101 ExpectString("obj1.x", "x");
6102 CHECK(CompileRun("obj2.x")->IsUndefined());
6104 CHECK(GetGlobalProperty(&context, "obj2")->
6105 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6107 ExpectString("obj1.x", "x");
6108 ExpectString("obj2.x", "x");
6110 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6111 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6113 CompileRun("Object.defineProperty(obj1, 'x',"
6114 "{ get: function() { return 'y'; }, configurable: true })");
6116 ExpectString("obj1.x", "y");
6117 ExpectString("obj2.x", "x");
6119 CompileRun("Object.defineProperty(obj2, 'x',"
6120 "{ get: function() { return 'y'; }, configurable: true })");
6122 ExpectString("obj1.x", "y");
6123 ExpectString("obj2.x", "y");
6125 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6126 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6128 CHECK(GetGlobalProperty(&context, "obj1")->
6129 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6130 CHECK(GetGlobalProperty(&context, "obj2")->
6131 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6133 ExpectString("obj1.x", "x");
6134 ExpectString("obj2.x", "x");
6136 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6137 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6139 // Define getters/setters, but now make them not configurable.
6140 CompileRun("Object.defineProperty(obj1, 'x',"
6141 "{ get: function() { return 'z'; }, configurable: false })");
6142 CompileRun("Object.defineProperty(obj2, 'x',"
6143 "{ get: function() { return 'z'; }, configurable: false })");
6145 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6146 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6148 ExpectString("obj1.x", "z");
6149 ExpectString("obj2.x", "z");
6151 CHECK(!GetGlobalProperty(&context, "obj1")->
6152 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6153 CHECK(!GetGlobalProperty(&context, "obj2")->
6154 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6156 ExpectString("obj1.x", "z");
6157 ExpectString("obj2.x", "z");
6161 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
6162 v8::Isolate* isolate = CcTest::isolate();
6163 v8::HandleScope scope(isolate);
6164 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6165 LocalContext context;
6167 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6168 CompileRun("var obj2 = {};");
6170 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
6173 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
6174 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
6177 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
6179 ExpectString("obj1.x", "x");
6180 ExpectString("obj2.x", "x");
6182 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
6183 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
6185 CHECK(!GetGlobalProperty(&context, "obj1")->
6186 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6187 CHECK(!GetGlobalProperty(&context, "obj2")->
6188 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
6191 v8::TryCatch try_catch;
6192 CompileRun("Object.defineProperty(obj1, 'x',"
6193 "{get: function() { return 'func'; }})");
6194 CHECK(try_catch.HasCaught());
6195 String::Utf8Value exception_value(try_catch.Exception());
6196 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
6199 v8::TryCatch try_catch;
6200 CompileRun("Object.defineProperty(obj2, 'x',"
6201 "{get: function() { return 'func'; }})");
6202 CHECK(try_catch.HasCaught());
6203 String::Utf8Value exception_value(try_catch.Exception());
6204 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
6209 static void Get239Value(Local<String> name,
6210 const v8::PropertyCallbackInfo<v8::Value>& info) {
6211 ApiTestFuzzer::Fuzz();
6212 CHECK_EQ(info.Data(), v8_str("donut"));
6213 CHECK_EQ(name, v8_str("239"));
6214 info.GetReturnValue().Set(name);
6218 THREADED_TEST(ElementAPIAccessor) {
6219 v8::Isolate* isolate = CcTest::isolate();
6220 v8::HandleScope scope(isolate);
6221 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6222 LocalContext context;
6224 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6225 CompileRun("var obj2 = {};");
6227 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
6231 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
6236 ExpectString("obj1[239]", "239");
6237 ExpectString("obj2[239]", "239");
6238 ExpectString("obj1['239']", "239");
6239 ExpectString("obj2['239']", "239");
6243 v8::Persistent<Value> xValue;
6246 static void SetXValue(Local<String> name,
6248 const v8::PropertyCallbackInfo<void>& info) {
6249 CHECK_EQ(value, v8_num(4));
6250 CHECK_EQ(info.Data(), v8_str("donut"));
6251 CHECK_EQ(name, v8_str("x"));
6252 CHECK(xValue.IsEmpty());
6253 xValue.Reset(info.GetIsolate(), value);
6257 THREADED_TEST(SimplePropertyWrite) {
6258 v8::Isolate* isolate = CcTest::isolate();
6259 v8::HandleScope scope(isolate);
6260 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6261 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6262 LocalContext context;
6263 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6264 Local<Script> script = v8_compile("obj.x = 4");
6265 for (int i = 0; i < 10; i++) {
6266 CHECK(xValue.IsEmpty());
6268 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6274 THREADED_TEST(SetterOnly) {
6275 v8::Isolate* isolate = CcTest::isolate();
6276 v8::HandleScope scope(isolate);
6277 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6278 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
6279 LocalContext context;
6280 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6281 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6282 for (int i = 0; i < 10; i++) {
6283 CHECK(xValue.IsEmpty());
6285 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6291 THREADED_TEST(NoAccessors) {
6292 v8::Isolate* isolate = CcTest::isolate();
6293 v8::HandleScope scope(isolate);
6294 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6295 templ->SetAccessor(v8_str("x"),
6296 static_cast<v8::AccessorGetterCallback>(NULL),
6299 LocalContext context;
6300 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6301 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6302 for (int i = 0; i < 10; i++) {
6308 static void XPropertyGetter(Local<Name> property,
6309 const v8::PropertyCallbackInfo<v8::Value>& info) {
6310 ApiTestFuzzer::Fuzz();
6311 CHECK(info.Data()->IsUndefined());
6312 info.GetReturnValue().Set(property);
6316 THREADED_TEST(NamedInterceptorPropertyRead) {
6317 v8::Isolate* isolate = CcTest::isolate();
6318 v8::HandleScope scope(isolate);
6319 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6320 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
6321 LocalContext context;
6322 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6323 Local<Script> script = v8_compile("obj.x");
6324 for (int i = 0; i < 10; i++) {
6325 Local<Value> result = script->Run();
6326 CHECK_EQ(result, v8_str("x"));
6331 THREADED_TEST(NamedInterceptorDictionaryIC) {
6332 v8::Isolate* isolate = CcTest::isolate();
6333 v8::HandleScope scope(isolate);
6334 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6335 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
6336 LocalContext context;
6337 // Create an object with a named interceptor.
6338 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
6339 Local<Script> script = v8_compile("interceptor_obj.x");
6340 for (int i = 0; i < 10; i++) {
6341 Local<Value> result = script->Run();
6342 CHECK_EQ(result, v8_str("x"));
6344 // Create a slow case object and a function accessing a property in
6345 // that slow case object (with dictionary probing in generated
6346 // code). Then force object with a named interceptor into slow-case,
6347 // pass it to the function, and check that the interceptor is called
6348 // instead of accessing the local property.
6349 Local<Value> result =
6350 CompileRun("function get_x(o) { return o.x; };"
6351 "var obj = { x : 42, y : 0 };"
6353 "for (var i = 0; i < 10; i++) get_x(obj);"
6354 "interceptor_obj.x = 42;"
6355 "interceptor_obj.y = 10;"
6356 "delete interceptor_obj.y;"
6357 "get_x(interceptor_obj)");
6358 CHECK_EQ(result, v8_str("x"));
6362 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
6363 v8::Isolate* isolate = CcTest::isolate();
6364 v8::HandleScope scope(isolate);
6365 v8::Local<Context> context1 = Context::New(isolate);
6368 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6369 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
6370 // Create an object with a named interceptor.
6371 v8::Local<v8::Object> object = templ->NewInstance();
6372 context1->Global()->Set(v8_str("interceptor_obj"), object);
6374 // Force the object into the slow case.
6375 CompileRun("interceptor_obj.y = 0;"
6376 "delete interceptor_obj.y;");
6380 // Introduce the object into a different context.
6381 // Repeat named loads to exercise ICs.
6382 LocalContext context2;
6383 context2->Global()->Set(v8_str("interceptor_obj"), object);
6384 Local<Value> result =
6385 CompileRun("function get_x(o) { return o.x; }"
6386 "interceptor_obj.x = 42;"
6387 "for (var i=0; i != 10; i++) {"
6388 " get_x(interceptor_obj);"
6390 "get_x(interceptor_obj)");
6391 // Check that the interceptor was actually invoked.
6392 CHECK_EQ(result, v8_str("x"));
6395 // Return to the original context and force some object to the slow case
6396 // to cause the NormalizedMapCache to verify.
6398 CompileRun("var obj = { x : 0 }; delete obj.x;");
6403 static void SetXOnPrototypeGetter(
6404 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
6405 // Set x on the prototype object and do not handle the get request.
6406 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
6407 proto.As<v8::Object>()->Set(v8_str("x"),
6408 v8::Integer::New(info.GetIsolate(), 23));
6412 // This is a regression test for http://crbug.com/20104. Map
6413 // transitions should not interfere with post interceptor lookup.
6414 THREADED_TEST(NamedInterceptorMapTransitionRead) {
6415 v8::Isolate* isolate = CcTest::isolate();
6416 v8::HandleScope scope(isolate);
6417 Local<v8::FunctionTemplate> function_template =
6418 v8::FunctionTemplate::New(isolate);
6419 Local<v8::ObjectTemplate> instance_template
6420 = function_template->InstanceTemplate();
6421 instance_template->SetHandler(
6422 v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
6423 LocalContext context;
6424 context->Global()->Set(v8_str("F"), function_template->GetFunction());
6425 // Create an instance of F and introduce a map transition for x.
6426 CompileRun("var o = new F(); o.x = 23;");
6427 // Create an instance of F and invoke the getter. The result should be 23.
6428 Local<Value> result = CompileRun("o = new F(); o.x");
6429 CHECK_EQ(result->Int32Value(), 23);
6433 static void IndexedPropertyGetter(
6435 const v8::PropertyCallbackInfo<v8::Value>& info) {
6436 ApiTestFuzzer::Fuzz();
6438 info.GetReturnValue().Set(v8_num(625));
6443 static void IndexedPropertySetter(
6446 const v8::PropertyCallbackInfo<v8::Value>& info) {
6447 ApiTestFuzzer::Fuzz();
6449 info.GetReturnValue().Set(value);
6454 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
6455 v8::Isolate* isolate = CcTest::isolate();
6456 v8::HandleScope scope(isolate);
6457 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6458 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
6459 IndexedPropertyGetter, IndexedPropertySetter));
6460 LocalContext context;
6461 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6462 Local<Script> getter_script = v8_compile(
6463 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6464 Local<Script> setter_script = v8_compile(
6465 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6468 Local<Script> interceptor_setter_script = v8_compile(
6469 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6471 "obj.foo;"); // This setter should not run, due to the interceptor.
6472 Local<Script> interceptor_getter_script = v8_compile(
6474 Local<Value> result = getter_script->Run();
6475 CHECK_EQ(v8_num(5), result);
6476 result = setter_script->Run();
6477 CHECK_EQ(v8_num(23), result);
6478 result = interceptor_setter_script->Run();
6479 CHECK_EQ(v8_num(23), result);
6480 result = interceptor_getter_script->Run();
6481 CHECK_EQ(v8_num(625), result);
6485 static void UnboxedDoubleIndexedPropertyGetter(
6487 const v8::PropertyCallbackInfo<v8::Value>& info) {
6488 ApiTestFuzzer::Fuzz();
6490 info.GetReturnValue().Set(v8_num(index));
6495 static void UnboxedDoubleIndexedPropertySetter(
6498 const v8::PropertyCallbackInfo<v8::Value>& info) {
6499 ApiTestFuzzer::Fuzz();
6501 info.GetReturnValue().Set(v8_num(index));
6506 void UnboxedDoubleIndexedPropertyEnumerator(
6507 const v8::PropertyCallbackInfo<v8::Array>& info) {
6508 // Force the list of returned keys to be stored in a FastDoubleArray.
6509 Local<Script> indexed_property_names_script = v8_compile(
6510 "keys = new Array(); keys[125000] = 1;"
6511 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6512 "keys.length = 25; keys;");
6513 Local<Value> result = indexed_property_names_script->Run();
6514 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6518 // Make sure that the the interceptor code in the runtime properly handles
6519 // merging property name lists for double-array-backed arrays.
6520 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6521 v8::Isolate* isolate = CcTest::isolate();
6522 v8::HandleScope scope(isolate);
6523 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6524 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
6525 UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter, 0,
6526 0, UnboxedDoubleIndexedPropertyEnumerator));
6527 LocalContext context;
6528 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6529 // When obj is created, force it to be Stored in a FastDoubleArray.
6530 Local<Script> create_unboxed_double_script = v8_compile(
6531 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6533 "for (x in obj) {key_count++;};"
6535 Local<Value> result = create_unboxed_double_script->Run();
6536 CHECK(result->ToObject(isolate)->HasRealIndexedProperty(2000));
6537 Local<Script> key_count_check = v8_compile("key_count;");
6538 result = key_count_check->Run();
6539 CHECK_EQ(v8_num(40013), result);
6543 void SloppyArgsIndexedPropertyEnumerator(
6544 const v8::PropertyCallbackInfo<v8::Array>& info) {
6545 // Force the list of returned keys to be stored in a Arguments object.
6546 Local<Script> indexed_property_names_script = v8_compile(
6548 " return arguments;"
6550 "keys = f(0, 1, 2, 3);"
6552 Local<Object> result =
6553 Local<Object>::Cast(indexed_property_names_script->Run());
6554 // Have to populate the handle manually, as it's not Cast-able.
6555 i::Handle<i::JSObject> o =
6556 v8::Utils::OpenHandle<Object, i::JSObject>(result);
6557 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6558 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6562 static void SloppyIndexedPropertyGetter(
6564 const v8::PropertyCallbackInfo<v8::Value>& info) {
6565 ApiTestFuzzer::Fuzz();
6567 info.GetReturnValue().Set(v8_num(index));
6572 // Make sure that the the interceptor code in the runtime properly handles
6573 // merging property name lists for non-string arguments arrays.
6574 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6575 v8::Isolate* isolate = CcTest::isolate();
6576 v8::HandleScope scope(isolate);
6577 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6578 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
6579 SloppyIndexedPropertyGetter, 0, 0, 0,
6580 SloppyArgsIndexedPropertyEnumerator));
6581 LocalContext context;
6582 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6583 Local<Script> create_args_script = v8_compile(
6584 "var key_count = 0;"
6585 "for (x in obj) {key_count++;} key_count;");
6586 Local<Value> result = create_args_script->Run();
6587 CHECK_EQ(v8_num(4), result);
6591 static void IdentityIndexedPropertyGetter(
6593 const v8::PropertyCallbackInfo<v8::Value>& info) {
6594 info.GetReturnValue().Set(index);
6598 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6599 v8::Isolate* isolate = CcTest::isolate();
6600 v8::HandleScope scope(isolate);
6601 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6603 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6605 LocalContext context;
6606 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6608 // Check fast object case.
6609 const char* fast_case_code =
6610 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6611 ExpectString(fast_case_code, "0");
6614 const char* slow_case_code =
6615 "obj.x = 1; delete obj.x;"
6616 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6617 ExpectString(slow_case_code, "1");
6621 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6622 v8::Isolate* isolate = CcTest::isolate();
6623 v8::HandleScope scope(isolate);
6624 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6626 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6628 LocalContext context;
6629 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6634 " for (var i = 0; i < 100; i++) {"
6636 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6642 ExpectString(code, "PASSED");
6646 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6647 v8::Isolate* isolate = CcTest::isolate();
6648 v8::HandleScope scope(isolate);
6649 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6651 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6653 LocalContext context;
6654 Local<v8::Object> obj = templ->NewInstance();
6655 obj->TurnOnAccessCheck();
6656 context->Global()->Set(v8_str("obj"), obj);
6659 "var result = 'PASSED';"
6660 "for (var i = 0; i < 100; i++) {"
6663 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6670 ExpectString(code, "PASSED");
6674 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6675 i::FLAG_allow_natives_syntax = true;
6676 v8::Isolate* isolate = CcTest::isolate();
6677 v8::HandleScope scope(isolate);
6678 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6680 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6682 LocalContext context;
6683 Local<v8::Object> obj = templ->NewInstance();
6684 context->Global()->Set(v8_str("obj"), obj);
6687 "var result = 'PASSED';"
6688 "for (var i = 0; i < 100; i++) {"
6689 " var expected = i;"
6691 " %EnableAccessChecks(obj);"
6696 " result = 'Should not have reached this!';"
6698 " } else if (v != expected) {"
6699 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6707 " if (i == 5) %DisableAccessChecks(obj);"
6710 ExpectString(code, "PASSED");
6714 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6715 v8::Isolate* isolate = CcTest::isolate();
6716 v8::HandleScope scope(isolate);
6717 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6719 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6721 LocalContext context;
6722 Local<v8::Object> obj = templ->NewInstance();
6723 context->Global()->Set(v8_str("obj"), obj);
6727 " for (var i = 0; i < 100; i++) {"
6729 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6735 ExpectString(code, "PASSED");
6739 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6740 v8::Isolate* isolate = CcTest::isolate();
6741 v8::HandleScope scope(isolate);
6742 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6744 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6746 LocalContext context;
6747 Local<v8::Object> obj = templ->NewInstance();
6748 context->Global()->Set(v8_str("obj"), obj);
6752 " for (var i = 0; i < 100; i++) {"
6753 " var expected = i;"
6757 " expected = undefined;"
6760 " /* probe minimal Smi number on 32-bit platforms */"
6761 " key = -(1 << 30);"
6762 " expected = undefined;"
6765 " /* probe minimal Smi number on 64-bit platforms */"
6767 " expected = undefined;"
6769 " var v = obj[key];"
6770 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6776 ExpectString(code, "PASSED");
6780 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6781 v8::Isolate* isolate = CcTest::isolate();
6782 v8::HandleScope scope(isolate);
6783 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6785 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6787 LocalContext context;
6788 Local<v8::Object> obj = templ->NewInstance();
6789 context->Global()->Set(v8_str("obj"), obj);
6793 " for (var i = 0; i < 100; i++) {"
6794 " var expected = i;"
6798 " expected = undefined;"
6800 " var v = obj[key];"
6801 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6807 ExpectString(code, "PASSED");
6811 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6812 v8::Isolate* isolate = CcTest::isolate();
6813 v8::HandleScope scope(isolate);
6814 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6816 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6818 LocalContext context;
6819 Local<v8::Object> obj = templ->NewInstance();
6820 context->Global()->Set(v8_str("obj"), obj);
6823 "var original = obj;"
6825 " for (var i = 0; i < 100; i++) {"
6826 " var expected = i;"
6828 " obj = {50: 'foobar'};"
6829 " expected = 'foobar';"
6832 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6833 " if (i == 50) obj = original;"
6839 ExpectString(code, "PASSED");
6843 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6844 v8::Isolate* isolate = CcTest::isolate();
6845 v8::HandleScope scope(isolate);
6846 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6848 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6850 LocalContext context;
6851 Local<v8::Object> obj = templ->NewInstance();
6852 context->Global()->Set(v8_str("obj"), obj);
6855 "var original = obj;"
6857 " for (var i = 0; i < 100; i++) {"
6858 " var expected = i;"
6861 " expected = undefined;"
6864 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6865 " if (i == 5) obj = original;"
6871 ExpectString(code, "PASSED");
6875 THREADED_TEST(IndexedInterceptorOnProto) {
6876 v8::Isolate* isolate = CcTest::isolate();
6877 v8::HandleScope scope(isolate);
6878 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6880 v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
6882 LocalContext context;
6883 Local<v8::Object> obj = templ->NewInstance();
6884 context->Global()->Set(v8_str("obj"), obj);
6887 "var o = {__proto__: obj};"
6889 " for (var i = 0; i < 100; i++) {"
6891 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6897 ExpectString(code, "PASSED");
6901 THREADED_TEST(MultiContexts) {
6902 v8::Isolate* isolate = CcTest::isolate();
6903 v8::HandleScope scope(isolate);
6904 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6905 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6908 Local<String> password = v8_str("Password");
6910 // Create an environment
6911 LocalContext context0(0, templ);
6912 context0->SetSecurityToken(password);
6913 v8::Handle<v8::Object> global0 = context0->Global();
6914 global0->Set(v8_str("custom"), v8_num(1234));
6915 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6917 // Create an independent environment
6918 LocalContext context1(0, templ);
6919 context1->SetSecurityToken(password);
6920 v8::Handle<v8::Object> global1 = context1->Global();
6921 global1->Set(v8_str("custom"), v8_num(1234));
6922 CHECK_NE(global0, global1);
6923 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6924 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6926 // Now create a new context with the old global
6927 LocalContext context2(0, templ, global1);
6928 context2->SetSecurityToken(password);
6929 v8::Handle<v8::Object> global2 = context2->Global();
6930 CHECK_EQ(global1, global2);
6931 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6932 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6936 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6937 // Make sure that functions created by cloning boilerplates cannot
6938 // communicate through their __proto__ field.
6940 v8::HandleScope scope(CcTest::isolate());
6943 v8::Handle<v8::Object> global0 =
6945 v8::Handle<v8::Object> object0 =
6946 global0->Get(v8_str("Object")).As<v8::Object>();
6947 v8::Handle<v8::Object> tostring0 =
6948 object0->Get(v8_str("toString")).As<v8::Object>();
6949 v8::Handle<v8::Object> proto0 =
6950 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6951 proto0->Set(v8_str("custom"), v8_num(1234));
6954 v8::Handle<v8::Object> global1 =
6956 v8::Handle<v8::Object> object1 =
6957 global1->Get(v8_str("Object")).As<v8::Object>();
6958 v8::Handle<v8::Object> tostring1 =
6959 object1->Get(v8_str("toString")).As<v8::Object>();
6960 v8::Handle<v8::Object> proto1 =
6961 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6962 CHECK(!proto1->Has(v8_str("custom")));
6966 THREADED_TEST(Regress892105) {
6967 // Make sure that object and array literals created by cloning
6968 // boilerplates cannot communicate through their __proto__
6969 // field. This is rather difficult to check, but we try to add stuff
6970 // to Object.prototype and Array.prototype and create a new
6971 // environment. This should succeed.
6973 v8::HandleScope scope(CcTest::isolate());
6975 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6976 "Array.prototype.arr = 4567;"
6980 Local<Script> script0 = v8_compile(source);
6981 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6984 Local<Script> script1 = v8_compile(source);
6985 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6989 THREADED_TEST(UndetectableObject) {
6991 v8::HandleScope scope(env->GetIsolate());
6993 Local<v8::FunctionTemplate> desc =
6994 v8::FunctionTemplate::New(env->GetIsolate());
6995 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6997 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6998 env->Global()->Set(v8_str("undetectable"), obj);
7000 ExpectString("undetectable.toString()", "[object Object]");
7001 ExpectString("typeof undetectable", "undefined");
7002 ExpectString("typeof(undetectable)", "undefined");
7003 ExpectBoolean("typeof undetectable == 'undefined'", true);
7004 ExpectBoolean("typeof undetectable == 'object'", false);
7005 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7006 ExpectBoolean("!undetectable", true);
7008 ExpectObject("true&&undetectable", obj);
7009 ExpectBoolean("false&&undetectable", false);
7010 ExpectBoolean("true||undetectable", true);
7011 ExpectObject("false||undetectable", obj);
7013 ExpectObject("undetectable&&true", obj);
7014 ExpectObject("undetectable&&false", obj);
7015 ExpectBoolean("undetectable||true", true);
7016 ExpectBoolean("undetectable||false", false);
7018 ExpectBoolean("undetectable==null", true);
7019 ExpectBoolean("null==undetectable", true);
7020 ExpectBoolean("undetectable==undefined", true);
7021 ExpectBoolean("undefined==undetectable", true);
7022 ExpectBoolean("undetectable==undetectable", true);
7025 ExpectBoolean("undetectable===null", false);
7026 ExpectBoolean("null===undetectable", false);
7027 ExpectBoolean("undetectable===undefined", false);
7028 ExpectBoolean("undefined===undetectable", false);
7029 ExpectBoolean("undetectable===undetectable", true);
7033 THREADED_TEST(VoidLiteral) {
7035 v8::Isolate* isolate = env->GetIsolate();
7036 v8::HandleScope scope(isolate);
7038 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7039 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7041 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
7042 env->Global()->Set(v8_str("undetectable"), obj);
7044 ExpectBoolean("undefined == void 0", true);
7045 ExpectBoolean("undetectable == void 0", true);
7046 ExpectBoolean("null == void 0", true);
7047 ExpectBoolean("undefined === void 0", true);
7048 ExpectBoolean("undetectable === void 0", false);
7049 ExpectBoolean("null === void 0", false);
7051 ExpectBoolean("void 0 == undefined", true);
7052 ExpectBoolean("void 0 == undetectable", true);
7053 ExpectBoolean("void 0 == null", true);
7054 ExpectBoolean("void 0 === undefined", true);
7055 ExpectBoolean("void 0 === undetectable", false);
7056 ExpectBoolean("void 0 === null", false);
7058 ExpectString("(function() {"
7060 " return x === void 0;"
7062 " return e.toString();"
7065 "ReferenceError: x is not defined");
7066 ExpectString("(function() {"
7068 " return void 0 === x;"
7070 " return e.toString();"
7073 "ReferenceError: x is not defined");
7077 THREADED_TEST(ExtensibleOnUndetectable) {
7079 v8::Isolate* isolate = env->GetIsolate();
7080 v8::HandleScope scope(isolate);
7082 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
7083 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
7085 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
7086 env->Global()->Set(v8_str("undetectable"), obj);
7088 Local<String> source = v8_str("undetectable.x = 42;"
7091 Local<Script> script = v8_compile(source);
7093 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
7095 ExpectBoolean("Object.isExtensible(undetectable)", true);
7097 source = v8_str("Object.preventExtensions(undetectable);");
7098 script = v8_compile(source);
7100 ExpectBoolean("Object.isExtensible(undetectable)", false);
7102 source = v8_str("undetectable.y = 2000;");
7103 script = v8_compile(source);
7105 ExpectBoolean("undetectable.y == undefined", true);
7110 THREADED_TEST(UndetectableString) {
7112 v8::HandleScope scope(env->GetIsolate());
7114 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
7115 String::kUndetectableString);
7116 env->Global()->Set(v8_str("undetectable"), obj);
7118 ExpectString("undetectable", "foo");
7119 ExpectString("typeof undetectable", "undefined");
7120 ExpectString("typeof(undetectable)", "undefined");
7121 ExpectBoolean("typeof undetectable == 'undefined'", true);
7122 ExpectBoolean("typeof undetectable == 'string'", false);
7123 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
7124 ExpectBoolean("!undetectable", true);
7126 ExpectObject("true&&undetectable", obj);
7127 ExpectBoolean("false&&undetectable", false);
7128 ExpectBoolean("true||undetectable", true);
7129 ExpectObject("false||undetectable", obj);
7131 ExpectObject("undetectable&&true", obj);
7132 ExpectObject("undetectable&&false", obj);
7133 ExpectBoolean("undetectable||true", true);
7134 ExpectBoolean("undetectable||false", false);
7136 ExpectBoolean("undetectable==null", true);
7137 ExpectBoolean("null==undetectable", true);
7138 ExpectBoolean("undetectable==undefined", true);
7139 ExpectBoolean("undefined==undetectable", true);
7140 ExpectBoolean("undetectable==undetectable", true);
7143 ExpectBoolean("undetectable===null", false);
7144 ExpectBoolean("null===undetectable", false);
7145 ExpectBoolean("undetectable===undefined", false);
7146 ExpectBoolean("undefined===undetectable", false);
7147 ExpectBoolean("undetectable===undetectable", true);
7151 TEST(UndetectableOptimized) {
7152 i::FLAG_allow_natives_syntax = true;
7154 v8::HandleScope scope(env->GetIsolate());
7156 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
7157 String::kUndetectableString);
7158 env->Global()->Set(v8_str("undetectable"), obj);
7159 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
7162 "function testBranch() {"
7163 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
7164 " if (%_IsUndetectableObject(detectable)) throw 2;"
7166 "function testBool() {"
7167 " var b1 = !%_IsUndetectableObject(undetectable);"
7168 " var b2 = %_IsUndetectableObject(detectable);"
7173 "%OptimizeFunctionOnNextCall(testBranch);"
7174 "%OptimizeFunctionOnNextCall(testBool);"
7175 "for (var i = 0; i < 10; i++) {"
7184 // The point of this test is type checking. We run it only so compilers
7185 // don't complain about an unused function.
7186 TEST(PersistentHandles) {
7188 v8::Isolate* isolate = CcTest::isolate();
7189 v8::HandleScope scope(isolate);
7190 Local<String> str = v8_str("foo");
7191 v8::Persistent<String> p_str(isolate, str);
7193 Local<Script> scr = v8_compile("");
7194 v8::Persistent<Script> p_scr(isolate, scr);
7196 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
7197 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
7202 static void HandleLogDelegator(
7203 const v8::FunctionCallbackInfo<v8::Value>& args) {
7204 ApiTestFuzzer::Fuzz();
7208 THREADED_TEST(GlobalObjectTemplate) {
7209 v8::Isolate* isolate = CcTest::isolate();
7210 v8::HandleScope handle_scope(isolate);
7211 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
7212 global_template->Set(v8_str("JSNI_Log"),
7213 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
7214 v8::Local<Context> context = Context::New(isolate, 0, global_template);
7215 Context::Scope context_scope(context);
7216 CompileRun("JSNI_Log('LOG')");
7220 static const char* kSimpleExtensionSource =
7226 TEST(SimpleExtensions) {
7227 v8::HandleScope handle_scope(CcTest::isolate());
7228 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
7229 const char* extension_names[] = { "simpletest" };
7230 v8::ExtensionConfiguration extensions(1, extension_names);
7231 v8::Handle<Context> context =
7232 Context::New(CcTest::isolate(), &extensions);
7233 Context::Scope lock(context);
7234 v8::Handle<Value> result = CompileRun("Foo()");
7235 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7239 static const char* kStackTraceFromExtensionSource =
7241 " throw new Error();"
7248 TEST(StackTraceInExtension) {
7249 v8::HandleScope handle_scope(CcTest::isolate());
7250 v8::RegisterExtension(new Extension("stacktracetest",
7251 kStackTraceFromExtensionSource));
7252 const char* extension_names[] = { "stacktracetest" };
7253 v8::ExtensionConfiguration extensions(1, extension_names);
7254 v8::Handle<Context> context =
7255 Context::New(CcTest::isolate(), &extensions);
7256 Context::Scope lock(context);
7257 CompileRun("function user() { bar(); }"
7259 "try{ user(); } catch (e) { error = e; }");
7260 CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
7261 CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
7262 CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
7266 TEST(NullExtensions) {
7267 v8::HandleScope handle_scope(CcTest::isolate());
7268 v8::RegisterExtension(new Extension("nulltest", NULL));
7269 const char* extension_names[] = { "nulltest" };
7270 v8::ExtensionConfiguration extensions(1, extension_names);
7271 v8::Handle<Context> context =
7272 Context::New(CcTest::isolate(), &extensions);
7273 Context::Scope lock(context);
7274 v8::Handle<Value> result = CompileRun("1+3");
7275 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7279 static const char* kEmbeddedExtensionSource =
7280 "function Ret54321(){return 54321;}~~@@$"
7281 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
7282 static const int kEmbeddedExtensionSourceValidLen = 34;
7285 TEST(ExtensionMissingSourceLength) {
7286 v8::HandleScope handle_scope(CcTest::isolate());
7287 v8::RegisterExtension(new Extension("srclentest_fail",
7288 kEmbeddedExtensionSource));
7289 const char* extension_names[] = { "srclentest_fail" };
7290 v8::ExtensionConfiguration extensions(1, extension_names);
7291 v8::Handle<Context> context =
7292 Context::New(CcTest::isolate(), &extensions);
7293 CHECK_EQ(0, *context);
7297 TEST(ExtensionWithSourceLength) {
7298 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7299 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7300 v8::HandleScope handle_scope(CcTest::isolate());
7301 i::ScopedVector<char> extension_name(32);
7302 i::SNPrintF(extension_name, "ext #%d", source_len);
7303 v8::RegisterExtension(new Extension(extension_name.start(),
7304 kEmbeddedExtensionSource, 0, 0,
7306 const char* extension_names[1] = { extension_name.start() };
7307 v8::ExtensionConfiguration extensions(1, extension_names);
7308 v8::Handle<Context> context =
7309 Context::New(CcTest::isolate(), &extensions);
7310 if (source_len == kEmbeddedExtensionSourceValidLen) {
7311 Context::Scope lock(context);
7312 v8::Handle<Value> result = CompileRun("Ret54321()");
7313 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
7315 // Anything but exactly the right length should fail to compile.
7316 CHECK_EQ(0, *context);
7322 static const char* kEvalExtensionSource1 =
7323 "function UseEval1() {"
7325 " return eval('x');"
7329 static const char* kEvalExtensionSource2 =
7333 " return eval('x');"
7335 " this.UseEval2 = e;"
7339 TEST(UseEvalFromExtension) {
7340 v8::HandleScope handle_scope(CcTest::isolate());
7341 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7342 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7343 const char* extension_names[] = { "evaltest1", "evaltest2" };
7344 v8::ExtensionConfiguration extensions(2, extension_names);
7345 v8::Handle<Context> context =
7346 Context::New(CcTest::isolate(), &extensions);
7347 Context::Scope lock(context);
7348 v8::Handle<Value> result = CompileRun("UseEval1()");
7349 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7350 result = CompileRun("UseEval2()");
7351 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7355 static const char* kWithExtensionSource1 =
7356 "function UseWith1() {"
7358 " with({x:87}) { return x; }"
7363 static const char* kWithExtensionSource2 =
7367 " with ({x:87}) { return x; }"
7369 " this.UseWith2 = e;"
7373 TEST(UseWithFromExtension) {
7374 v8::HandleScope handle_scope(CcTest::isolate());
7375 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7376 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7377 const char* extension_names[] = { "withtest1", "withtest2" };
7378 v8::ExtensionConfiguration extensions(2, extension_names);
7379 v8::Handle<Context> context =
7380 Context::New(CcTest::isolate(), &extensions);
7381 Context::Scope lock(context);
7382 v8::Handle<Value> result = CompileRun("UseWith1()");
7383 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7384 result = CompileRun("UseWith2()");
7385 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7389 TEST(AutoExtensions) {
7390 v8::HandleScope handle_scope(CcTest::isolate());
7391 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7392 extension->set_auto_enable(true);
7393 v8::RegisterExtension(extension);
7394 v8::Handle<Context> context =
7395 Context::New(CcTest::isolate());
7396 Context::Scope lock(context);
7397 v8::Handle<Value> result = CompileRun("Foo()");
7398 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7402 static const char* kSyntaxErrorInExtensionSource =
7406 // Test that a syntax error in an extension does not cause a fatal
7407 // error but results in an empty context.
7408 TEST(SyntaxErrorExtensions) {
7409 v8::HandleScope handle_scope(CcTest::isolate());
7410 v8::RegisterExtension(new Extension("syntaxerror",
7411 kSyntaxErrorInExtensionSource));
7412 const char* extension_names[] = { "syntaxerror" };
7413 v8::ExtensionConfiguration extensions(1, extension_names);
7414 v8::Handle<Context> context =
7415 Context::New(CcTest::isolate(), &extensions);
7416 CHECK(context.IsEmpty());
7420 static const char* kExceptionInExtensionSource =
7424 // Test that an exception when installing an extension does not cause
7425 // a fatal error but results in an empty context.
7426 TEST(ExceptionExtensions) {
7427 v8::HandleScope handle_scope(CcTest::isolate());
7428 v8::RegisterExtension(new Extension("exception",
7429 kExceptionInExtensionSource));
7430 const char* extension_names[] = { "exception" };
7431 v8::ExtensionConfiguration extensions(1, extension_names);
7432 v8::Handle<Context> context =
7433 Context::New(CcTest::isolate(), &extensions);
7434 CHECK(context.IsEmpty());
7438 static const char* kNativeCallInExtensionSource =
7439 "function call_runtime_last_index_of(x) {"
7440 " return %StringLastIndexOf(x, 'bob', 10);"
7444 static const char* kNativeCallTest =
7445 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7447 // Test that a native runtime calls are supported in extensions.
7448 TEST(NativeCallInExtensions) {
7449 v8::HandleScope handle_scope(CcTest::isolate());
7450 v8::RegisterExtension(new Extension("nativecall",
7451 kNativeCallInExtensionSource));
7452 const char* extension_names[] = { "nativecall" };
7453 v8::ExtensionConfiguration extensions(1, extension_names);
7454 v8::Handle<Context> context =
7455 Context::New(CcTest::isolate(), &extensions);
7456 Context::Scope lock(context);
7457 v8::Handle<Value> result = CompileRun(kNativeCallTest);
7458 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
7462 class NativeFunctionExtension : public Extension {
7464 NativeFunctionExtension(const char* name,
7466 v8::FunctionCallback fun = &Echo)
7467 : Extension(name, source),
7470 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7471 v8::Isolate* isolate,
7472 v8::Handle<v8::String> name) {
7473 return v8::FunctionTemplate::New(isolate, function_);
7476 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7477 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7480 v8::FunctionCallback function_;
7484 TEST(NativeFunctionDeclaration) {
7485 v8::HandleScope handle_scope(CcTest::isolate());
7486 const char* name = "nativedecl";
7487 v8::RegisterExtension(new NativeFunctionExtension(name,
7488 "native function foo();"));
7489 const char* extension_names[] = { name };
7490 v8::ExtensionConfiguration extensions(1, extension_names);
7491 v8::Handle<Context> context =
7492 Context::New(CcTest::isolate(), &extensions);
7493 Context::Scope lock(context);
7494 v8::Handle<Value> result = CompileRun("foo(42);");
7495 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7499 TEST(NativeFunctionDeclarationError) {
7500 v8::HandleScope handle_scope(CcTest::isolate());
7501 const char* name = "nativedeclerr";
7502 // Syntax error in extension code.
7503 v8::RegisterExtension(new NativeFunctionExtension(name,
7504 "native\nfunction foo();"));
7505 const char* extension_names[] = { name };
7506 v8::ExtensionConfiguration extensions(1, extension_names);
7507 v8::Handle<Context> context =
7508 Context::New(CcTest::isolate(), &extensions);
7509 CHECK(context.IsEmpty());
7513 TEST(NativeFunctionDeclarationErrorEscape) {
7514 v8::HandleScope handle_scope(CcTest::isolate());
7515 const char* name = "nativedeclerresc";
7516 // Syntax error in extension code - escape code in "native" means that
7517 // it's not treated as a keyword.
7518 v8::RegisterExtension(new NativeFunctionExtension(
7520 "nativ\\u0065 function foo();"));
7521 const char* extension_names[] = { name };
7522 v8::ExtensionConfiguration extensions(1, extension_names);
7523 v8::Handle<Context> context =
7524 Context::New(CcTest::isolate(), &extensions);
7525 CHECK(context.IsEmpty());
7529 static void CheckDependencies(const char* name, const char* expected) {
7530 v8::HandleScope handle_scope(CcTest::isolate());
7531 v8::ExtensionConfiguration config(1, &name);
7532 LocalContext context(&config);
7533 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7534 context->Global()->Get(v8_str("loaded")));
7545 THREADED_TEST(ExtensionDependency) {
7546 static const char* kEDeps[] = { "D" };
7547 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7548 static const char* kDDeps[] = { "B", "C" };
7549 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7550 static const char* kBCDeps[] = { "A" };
7551 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7552 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7553 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7554 CheckDependencies("A", "undefinedA");
7555 CheckDependencies("B", "undefinedAB");
7556 CheckDependencies("C", "undefinedAC");
7557 CheckDependencies("D", "undefinedABCD");
7558 CheckDependencies("E", "undefinedABCDE");
7559 v8::HandleScope handle_scope(CcTest::isolate());
7560 static const char* exts[2] = { "C", "E" };
7561 v8::ExtensionConfiguration config(2, exts);
7562 LocalContext context(&config);
7563 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7567 static const char* kExtensionTestScript =
7568 "native function A();"
7569 "native function B();"
7570 "native function C();"
7572 " if (i == 0) return A();"
7573 " if (i == 1) return B();"
7574 " if (i == 2) return C();"
7578 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7579 ApiTestFuzzer::Fuzz();
7580 if (args.IsConstructCall()) {
7581 args.This()->Set(v8_str("data"), args.Data());
7582 args.GetReturnValue().SetNull();
7585 args.GetReturnValue().Set(args.Data());
7589 class FunctionExtension : public Extension {
7591 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7592 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7593 v8::Isolate* isolate,
7594 v8::Handle<String> name);
7598 static int lookup_count = 0;
7599 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7600 v8::Isolate* isolate, v8::Handle<String> name) {
7602 if (name->Equals(v8_str("A"))) {
7603 return v8::FunctionTemplate::New(
7604 isolate, CallFun, v8::Integer::New(isolate, 8));
7605 } else if (name->Equals(v8_str("B"))) {
7606 return v8::FunctionTemplate::New(
7607 isolate, CallFun, v8::Integer::New(isolate, 7));
7608 } else if (name->Equals(v8_str("C"))) {
7609 return v8::FunctionTemplate::New(
7610 isolate, CallFun, v8::Integer::New(isolate, 6));
7612 return v8::Handle<v8::FunctionTemplate>();
7617 THREADED_TEST(FunctionLookup) {
7618 v8::RegisterExtension(new FunctionExtension());
7619 v8::HandleScope handle_scope(CcTest::isolate());
7620 static const char* exts[1] = { "functiontest" };
7621 v8::ExtensionConfiguration config(1, exts);
7622 LocalContext context(&config);
7623 CHECK_EQ(3, lookup_count);
7624 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7625 CompileRun("Foo(0)"));
7626 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7627 CompileRun("Foo(1)"));
7628 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7629 CompileRun("Foo(2)"));
7633 THREADED_TEST(NativeFunctionConstructCall) {
7634 v8::RegisterExtension(new FunctionExtension());
7635 v8::HandleScope handle_scope(CcTest::isolate());
7636 static const char* exts[1] = { "functiontest" };
7637 v8::ExtensionConfiguration config(1, exts);
7638 LocalContext context(&config);
7639 for (int i = 0; i < 10; i++) {
7640 // Run a few times to ensure that allocation of objects doesn't
7641 // change behavior of a constructor function.
7642 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7643 CompileRun("(new A()).data"));
7644 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7645 CompileRun("(new B()).data"));
7646 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7647 CompileRun("(new C()).data"));
7652 static const char* last_location;
7653 static const char* last_message;
7654 void StoringErrorCallback(const char* location, const char* message) {
7655 if (last_location == NULL) {
7656 last_location = location;
7657 last_message = message;
7662 // ErrorReporting creates a circular extensions configuration and
7663 // tests that the fatal error handler gets called. This renders V8
7664 // unusable and therefore this test cannot be run in parallel.
7665 TEST(ErrorReporting) {
7666 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7667 static const char* aDeps[] = { "B" };
7668 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7669 static const char* bDeps[] = { "A" };
7670 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7671 last_location = NULL;
7672 v8::ExtensionConfiguration config(1, bDeps);
7673 v8::Handle<Context> context =
7674 Context::New(CcTest::isolate(), &config);
7675 CHECK(context.IsEmpty());
7676 CHECK_NE(last_location, NULL);
7680 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7681 v8::Handle<Value> data) {
7682 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7683 CHECK_EQ(v8::Undefined(CcTest::isolate()),
7684 message->GetScriptOrigin().ResourceName());
7685 message->GetLineNumber();
7686 message->GetSourceLine();
7690 THREADED_TEST(ErrorWithMissingScriptInfo) {
7691 LocalContext context;
7692 v8::HandleScope scope(context->GetIsolate());
7693 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7694 CompileRun("throw Error()");
7695 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7699 struct FlagAndPersistent {
7701 v8::Persistent<v8::Object> handle;
7705 static void SetFlag(const v8::PhantomCallbackData<FlagAndPersistent>& data) {
7706 data.GetParameter()->flag = true;
7710 static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7711 v8::Isolate* iso = CcTest::isolate();
7712 v8::HandleScope scope(iso);
7713 v8::Handle<Context> context = Context::New(iso);
7714 Context::Scope context_scope(context);
7716 FlagAndPersistent object_a, object_b;
7718 intptr_t big_heap_size;
7721 v8::HandleScope handle_scope(iso);
7722 Local<Object> a(v8::Object::New(iso));
7723 Local<Object> b(v8::Object::New(iso));
7724 object_a.handle.Reset(iso, a);
7725 object_b.handle.Reset(iso, b);
7727 a->Set(v8_str("x"), b);
7728 b->Set(v8_str("x"), a);
7731 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7733 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7735 // We are relying on this creating a big flag array and reserving the space
7737 v8::Handle<Value> big_array = CompileRun("new Array(50000)");
7738 a->Set(v8_str("y"), big_array);
7739 big_heap_size = CcTest::heap()->SizeOfObjects();
7742 object_a.flag = false;
7743 object_b.flag = false;
7744 object_a.handle.SetPhantom(&object_a, &SetFlag);
7745 object_b.handle.SetPhantom(&object_b, &SetFlag);
7746 CHECK(!object_b.handle.IsIndependent());
7747 object_a.handle.MarkIndependent();
7748 object_b.handle.MarkIndependent();
7749 CHECK(object_b.handle.IsIndependent());
7751 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7753 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7755 // A single GC should be enough to reclaim the memory, since we are using
7757 CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
7758 CHECK(object_a.flag);
7759 CHECK(object_b.flag);
7763 THREADED_TEST(IndependentWeakHandle) {
7764 IndependentWeakHandle(false, false);
7765 IndependentWeakHandle(false, true);
7766 IndependentWeakHandle(true, false);
7767 IndependentWeakHandle(true, true);
7773 explicit Trivial(int x) : x_(x) {}
7775 int x() { return x_; }
7776 void set_x(int x) { x_ = x; }
7785 Trivial2(int x, int y) : y_(y), x_(x) {}
7787 int x() { return x_; }
7788 void set_x(int x) { x_ = x; }
7790 int y() { return y_; }
7791 void set_y(int y) { y_ = y; }
7799 void CheckInternalFields(
7800 const v8::InternalFieldsCallbackData<Trivial, Trivial2>& data) {
7801 Trivial* t1 = data.GetInternalField1();
7802 Trivial2* t2 = data.GetInternalField2();
7803 CHECK_EQ(42, t1->x());
7804 CHECK_EQ(103, t2->x());
7806 t2->set_x(33550336);
7810 void InternalFieldCallback(bool global_gc) {
7812 v8::Isolate* isolate = env->GetIsolate();
7813 v8::HandleScope scope(isolate);
7815 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
7816 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
7819 instance_templ->SetInternalFieldCount(2);
7821 v8::HandleScope scope(isolate);
7822 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
7823 v8::Persistent<v8::Object> handle(isolate, obj);
7824 CHECK_EQ(2, obj->InternalFieldCount());
7825 CHECK(obj->GetInternalField(0)->IsUndefined());
7826 t1 = new Trivial(42);
7827 t2 = new Trivial2(103, 9);
7829 obj->SetAlignedPointerInInternalField(0, t1);
7830 t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
7831 CHECK_EQ(42, t1->x());
7833 obj->SetAlignedPointerInInternalField(1, t2);
7835 reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
7836 CHECK_EQ(103, t2->x());
7838 handle.SetPhantom(CheckInternalFields, 0, 1);
7840 handle.MarkIndependent();
7844 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7846 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7849 CHECK_EQ(1729, t1->x());
7850 CHECK_EQ(33550336, t2->x());
7857 THREADED_TEST(InternalFieldCallback) {
7858 InternalFieldCallback(false);
7859 InternalFieldCallback(true);
7863 static void ResetUseValueAndSetFlag(
7864 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7865 // Blink will reset the handle, and then use the other handle, so they
7866 // can't use the same backing slot.
7867 data.GetParameter()->handle.Reset();
7868 data.GetValue()->IsBoolean(); // Make sure the handle still works.
7869 data.GetParameter()->flag = true;
7873 static void ResetWeakHandle(bool global_gc) {
7874 v8::Isolate* iso = CcTest::isolate();
7875 v8::HandleScope scope(iso);
7876 v8::Handle<Context> context = Context::New(iso);
7877 Context::Scope context_scope(context);
7879 FlagAndPersistent object_a, object_b;
7882 v8::HandleScope handle_scope(iso);
7883 Local<Object> a(v8::Object::New(iso));
7884 Local<Object> b(v8::Object::New(iso));
7885 object_a.handle.Reset(iso, a);
7886 object_b.handle.Reset(iso, b);
7888 CcTest::heap()->CollectAllGarbage(
7889 TestHeap::Heap::kAbortIncrementalMarkingMask);
7891 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7895 object_a.flag = false;
7896 object_b.flag = false;
7897 object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
7898 object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
7900 object_a.handle.MarkIndependent();
7901 object_b.handle.MarkIndependent();
7902 CHECK(object_b.handle.IsIndependent());
7905 CcTest::heap()->CollectAllGarbage(
7906 TestHeap::Heap::kAbortIncrementalMarkingMask);
7908 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7910 CHECK(object_a.flag);
7911 CHECK(object_b.flag);
7915 THREADED_TEST(ResetWeakHandle) {
7916 ResetWeakHandle(false);
7917 ResetWeakHandle(true);
7921 static void InvokeScavenge() {
7922 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7926 static void InvokeMarkSweep() {
7927 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7931 static void ForceScavenge(
7932 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7933 data.GetParameter()->handle.Reset();
7934 data.GetParameter()->flag = true;
7939 static void ForceMarkSweep(
7940 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7941 data.GetParameter()->handle.Reset();
7942 data.GetParameter()->flag = true;
7947 THREADED_TEST(GCFromWeakCallbacks) {
7948 v8::Isolate* isolate = CcTest::isolate();
7949 v8::HandleScope scope(isolate);
7950 v8::Handle<Context> context = Context::New(isolate);
7951 Context::Scope context_scope(context);
7953 static const int kNumberOfGCTypes = 2;
7954 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7956 Callback gc_forcing_callback[kNumberOfGCTypes] =
7957 {&ForceScavenge, &ForceMarkSweep};
7959 typedef void (*GCInvoker)();
7960 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7962 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7963 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7964 FlagAndPersistent object;
7966 v8::HandleScope handle_scope(isolate);
7967 object.handle.Reset(isolate, v8::Object::New(isolate));
7969 object.flag = false;
7970 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7971 object.handle.MarkIndependent();
7972 invoke_gc[outer_gc]();
7979 static void RevivingCallback(
7980 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7981 data.GetParameter()->handle.ClearWeak();
7982 data.GetParameter()->flag = true;
7986 THREADED_TEST(IndependentHandleRevival) {
7987 v8::Isolate* isolate = CcTest::isolate();
7988 v8::HandleScope scope(isolate);
7989 v8::Handle<Context> context = Context::New(isolate);
7990 Context::Scope context_scope(context);
7992 FlagAndPersistent object;
7994 v8::HandleScope handle_scope(isolate);
7995 v8::Local<v8::Object> o = v8::Object::New(isolate);
7996 object.handle.Reset(isolate, o);
7997 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7998 v8::Local<String> y_str = v8_str("y");
7999 o->Set(y_str, y_str);
8001 object.flag = false;
8002 object.handle.SetWeak(&object, &RevivingCallback);
8003 object.handle.MarkIndependent();
8004 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
8006 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
8008 v8::HandleScope handle_scope(isolate);
8009 v8::Local<v8::Object> o =
8010 v8::Local<v8::Object>::New(isolate, object.handle);
8011 v8::Local<String> y_str = v8_str("y");
8012 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
8013 CHECK(o->Get(y_str)->Equals(y_str));
8018 v8::Handle<Function> args_fun;
8021 static void ArgumentsTestCallback(
8022 const v8::FunctionCallbackInfo<v8::Value>& args) {
8023 ApiTestFuzzer::Fuzz();
8024 v8::Isolate* isolate = args.GetIsolate();
8025 CHECK_EQ(args_fun, args.Callee());
8026 CHECK_EQ(3, args.Length());
8027 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
8028 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
8029 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
8030 CHECK_EQ(v8::Undefined(isolate), args[3]);
8031 v8::HandleScope scope(args.GetIsolate());
8032 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
8036 THREADED_TEST(Arguments) {
8037 v8::Isolate* isolate = CcTest::isolate();
8038 v8::HandleScope scope(isolate);
8039 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
8040 global->Set(v8_str("f"),
8041 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
8042 LocalContext context(NULL, global);
8043 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
8044 v8_compile("f(1, 2, 3)")->Run();
8048 static void NoBlockGetterX(Local<Name> name,
8049 const v8::PropertyCallbackInfo<v8::Value>&) {}
8052 static void NoBlockGetterI(uint32_t index,
8053 const v8::PropertyCallbackInfo<v8::Value>&) {
8057 static void PDeleter(Local<Name> name,
8058 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
8059 if (!name->Equals(v8_str("foo"))) {
8060 return; // not intercepted
8063 info.GetReturnValue().Set(false); // intercepted, don't delete the property
8067 static void IDeleter(uint32_t index,
8068 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
8070 return; // not intercepted
8073 info.GetReturnValue().Set(false); // intercepted, don't delete the property
8077 THREADED_TEST(Deleter) {
8078 v8::Isolate* isolate = CcTest::isolate();
8079 v8::HandleScope scope(isolate);
8080 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8081 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX, NULL,
8082 NULL, PDeleter, NULL));
8083 obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
8084 NoBlockGetterI, NULL, NULL, IDeleter, NULL));
8085 LocalContext context;
8086 context->Global()->Set(v8_str("k"), obj->NewInstance());
8092 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
8093 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
8095 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
8096 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
8098 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
8099 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
8101 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
8102 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
8106 static void GetK(Local<Name> name,
8107 const v8::PropertyCallbackInfo<v8::Value>& info) {
8108 ApiTestFuzzer::Fuzz();
8109 if (name->Equals(v8_str("foo")) ||
8110 name->Equals(v8_str("bar")) ||
8111 name->Equals(v8_str("baz"))) {
8112 info.GetReturnValue().SetUndefined();
8117 static void IndexedGetK(uint32_t index,
8118 const v8::PropertyCallbackInfo<v8::Value>& info) {
8119 ApiTestFuzzer::Fuzz();
8120 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
8124 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
8125 ApiTestFuzzer::Fuzz();
8126 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
8127 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
8128 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
8129 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
8130 info.GetReturnValue().Set(result);
8134 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
8135 ApiTestFuzzer::Fuzz();
8136 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
8137 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
8138 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
8139 info.GetReturnValue().Set(result);
8143 THREADED_TEST(Enumerators) {
8144 v8::Isolate* isolate = CcTest::isolate();
8145 v8::HandleScope scope(isolate);
8146 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8148 v8::NamedPropertyHandlerConfiguration(GetK, NULL, NULL, NULL, NamedEnum));
8149 obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
8150 IndexedGetK, NULL, NULL, NULL, IndexedEnum));
8151 LocalContext context;
8152 context->Global()->Set(v8_str("k"), obj->NewInstance());
8153 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
8158 "k[4294967295] = 0;"
8160 "k[4294967296] = 0;"
8164 "k[30000000000] = 0;"
8167 "for (var prop in k) {"
8168 " result.push(prop);"
8171 // Check that we get all the property names returned including the
8172 // ones from the enumerators in the right order: indexed properties
8173 // in numerical order, indexed interceptor properties, named
8174 // properties in insertion order, named interceptor properties.
8175 // This order is not mandated by the spec, so this test is just
8176 // documenting our behavior.
8177 CHECK_EQ(17, result->Length());
8178 // Indexed properties in numerical order.
8179 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
8180 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
8181 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
8182 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
8183 // Indexed interceptor properties in the order they are returned
8184 // from the enumerator interceptor.
8185 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
8186 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
8187 // Named properties in insertion order.
8188 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
8189 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
8190 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
8191 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
8192 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
8193 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
8194 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
8195 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
8196 // Named interceptor properties.
8197 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
8198 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
8199 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
8204 int p_getter_count2;
8207 static void PGetter(Local<String> name,
8208 const v8::PropertyCallbackInfo<v8::Value>& info) {
8209 ApiTestFuzzer::Fuzz();
8211 v8::Handle<v8::Object> global =
8212 info.GetIsolate()->GetCurrentContext()->Global();
8213 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
8214 if (name->Equals(v8_str("p1"))) {
8215 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
8216 } else if (name->Equals(v8_str("p2"))) {
8217 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
8218 } else if (name->Equals(v8_str("p3"))) {
8219 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
8220 } else if (name->Equals(v8_str("p4"))) {
8221 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
8226 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
8227 ApiTestFuzzer::Fuzz();
8228 LocalContext context;
8229 context->Global()->Set(v8_str("o1"), obj->NewInstance());
8231 "o1.__proto__ = { };"
8232 "var o2 = { __proto__: o1 };"
8233 "var o3 = { __proto__: o2 };"
8234 "var o4 = { __proto__: o3 };"
8235 "for (var i = 0; i < 10; i++) o4.p4;"
8236 "for (var i = 0; i < 10; i++) o3.p3;"
8237 "for (var i = 0; i < 10; i++) o2.p2;"
8238 "for (var i = 0; i < 10; i++) o1.p1;");
8242 static void PGetter2(Local<Name> name,
8243 const v8::PropertyCallbackInfo<v8::Value>& info) {
8244 ApiTestFuzzer::Fuzz();
8246 v8::Handle<v8::Object> global =
8247 info.GetIsolate()->GetCurrentContext()->Global();
8248 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
8249 if (name->Equals(v8_str("p1"))) {
8250 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
8251 } else if (name->Equals(v8_str("p2"))) {
8252 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
8253 } else if (name->Equals(v8_str("p3"))) {
8254 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
8255 } else if (name->Equals(v8_str("p4"))) {
8256 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
8261 THREADED_TEST(GetterHolders) {
8262 v8::Isolate* isolate = CcTest::isolate();
8263 v8::HandleScope scope(isolate);
8264 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8265 obj->SetAccessor(v8_str("p1"), PGetter);
8266 obj->SetAccessor(v8_str("p2"), PGetter);
8267 obj->SetAccessor(v8_str("p3"), PGetter);
8268 obj->SetAccessor(v8_str("p4"), PGetter);
8271 CHECK_EQ(40, p_getter_count);
8275 THREADED_TEST(PreInterceptorHolders) {
8276 v8::Isolate* isolate = CcTest::isolate();
8277 v8::HandleScope scope(isolate);
8278 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8279 obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
8280 p_getter_count2 = 0;
8282 CHECK_EQ(40, p_getter_count2);
8286 THREADED_TEST(ObjectInstantiation) {
8287 v8::Isolate* isolate = CcTest::isolate();
8288 v8::HandleScope scope(isolate);
8289 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
8290 templ->SetAccessor(v8_str("t"), PGetter2);
8291 LocalContext context;
8292 context->Global()->Set(v8_str("o"), templ->NewInstance());
8293 for (int i = 0; i < 100; i++) {
8294 v8::HandleScope inner_scope(CcTest::isolate());
8295 v8::Handle<v8::Object> obj = templ->NewInstance();
8296 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
8297 context->Global()->Set(v8_str("o2"), obj);
8298 v8::Handle<Value> value =
8299 CompileRun("o.__proto__ === o2.__proto__");
8300 CHECK_EQ(v8::True(isolate), value);
8301 context->Global()->Set(v8_str("o"), obj);
8306 static int StrCmp16(uint16_t* a, uint16_t* b) {
8308 if (*a == 0 && *b == 0) return 0;
8309 if (*a != *b) return 0 + *a - *b;
8316 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8318 if (n-- == 0) return 0;
8319 if (*a == 0 && *b == 0) return 0;
8320 if (*a != *b) return 0 + *a - *b;
8327 int GetUtf8Length(Handle<String> str) {
8328 int len = str->Utf8Length();
8330 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
8331 i::String::Flatten(istr);
8332 len = str->Utf8Length();
8338 THREADED_TEST(StringWrite) {
8339 LocalContext context;
8340 v8::HandleScope scope(context->GetIsolate());
8341 v8::Handle<String> str = v8_str("abcde");
8342 // abc<Icelandic eth><Unicode snowman>.
8343 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
8344 v8::Handle<String> str3 = v8::String::NewFromUtf8(
8345 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
8346 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
8347 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
8348 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
8349 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
8350 // single lead surrogate
8351 uint16_t lead[1] = { 0xd800 };
8352 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
8353 context->GetIsolate(), lead, v8::String::kNormalString, 1);
8354 // single trail surrogate
8355 uint16_t trail[1] = { 0xdc00 };
8356 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
8357 context->GetIsolate(), trail, v8::String::kNormalString, 1);
8359 uint16_t pair[2] = { 0xd800, 0xdc00 };
8360 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
8361 context->GetIsolate(), pair, v8::String::kNormalString, 2);
8362 const int kStride = 4; // Must match stride in for loops in JS below.
8365 "for (var i = 0; i < 0xd800; i += 4) {"
8366 " left = left + String.fromCharCode(i);"
8370 "for (var i = 0; i < 0xd800; i += 4) {"
8371 " right = String.fromCharCode(i) + right;"
8373 v8::Handle<v8::Object> global = context->Global();
8374 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
8375 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
8377 CHECK_EQ(5, str2->Length());
8378 CHECK_EQ(0xd800 / kStride, left_tree->Length());
8379 CHECK_EQ(0xd800 / kStride, right_tree->Length());
8382 char utf8buf[0xd800 * 3];
8387 memset(utf8buf, 0x1, 1000);
8388 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8390 CHECK_EQ(5, charlen);
8391 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8393 memset(utf8buf, 0x1, 1000);
8394 len = str2->WriteUtf8(utf8buf, 8, &charlen);
8396 CHECK_EQ(5, charlen);
8397 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
8399 memset(utf8buf, 0x1, 1000);
8400 len = str2->WriteUtf8(utf8buf, 7, &charlen);
8402 CHECK_EQ(4, charlen);
8403 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8405 memset(utf8buf, 0x1, 1000);
8406 len = str2->WriteUtf8(utf8buf, 6, &charlen);
8408 CHECK_EQ(4, charlen);
8409 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8411 memset(utf8buf, 0x1, 1000);
8412 len = str2->WriteUtf8(utf8buf, 5, &charlen);
8414 CHECK_EQ(4, charlen);
8415 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8417 memset(utf8buf, 0x1, 1000);
8418 len = str2->WriteUtf8(utf8buf, 4, &charlen);
8420 CHECK_EQ(3, charlen);
8421 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8423 memset(utf8buf, 0x1, 1000);
8424 len = str2->WriteUtf8(utf8buf, 3, &charlen);
8426 CHECK_EQ(3, charlen);
8427 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8429 memset(utf8buf, 0x1, 1000);
8430 len = str2->WriteUtf8(utf8buf, 2, &charlen);
8432 CHECK_EQ(2, charlen);
8433 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
8435 // allow orphan surrogates by default
8436 memset(utf8buf, 0x1, 1000);
8437 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8439 CHECK_EQ(8, charlen);
8440 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
8442 // replace orphan surrogates with unicode replacement character
8443 memset(utf8buf, 0x1, 1000);
8444 len = orphans_str->WriteUtf8(utf8buf,
8447 String::REPLACE_INVALID_UTF8);
8449 CHECK_EQ(8, charlen);
8450 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
8452 // replace single lead surrogate with unicode replacement character
8453 memset(utf8buf, 0x1, 1000);
8454 len = lead_str->WriteUtf8(utf8buf,
8457 String::REPLACE_INVALID_UTF8);
8459 CHECK_EQ(1, charlen);
8460 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8462 // replace single trail surrogate with unicode replacement character
8463 memset(utf8buf, 0x1, 1000);
8464 len = trail_str->WriteUtf8(utf8buf,
8467 String::REPLACE_INVALID_UTF8);
8469 CHECK_EQ(1, charlen);
8470 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8472 // do not replace / write anything if surrogate pair does not fit the buffer
8474 memset(utf8buf, 0x1, 1000);
8475 len = pair_str->WriteUtf8(utf8buf,
8478 String::REPLACE_INVALID_UTF8);
8480 CHECK_EQ(0, charlen);
8482 memset(utf8buf, 0x1, sizeof(utf8buf));
8483 len = GetUtf8Length(left_tree);
8485 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
8486 CHECK_EQ(utf8_expected, len);
8487 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8488 CHECK_EQ(utf8_expected, len);
8489 CHECK_EQ(0xd800 / kStride, charlen);
8490 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8491 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8492 CHECK_EQ(0xc0 - kStride,
8493 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8494 CHECK_EQ(1, utf8buf[utf8_expected]);
8496 memset(utf8buf, 0x1, sizeof(utf8buf));
8497 len = GetUtf8Length(right_tree);
8498 CHECK_EQ(utf8_expected, len);
8499 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8500 CHECK_EQ(utf8_expected, len);
8501 CHECK_EQ(0xd800 / kStride, charlen);
8502 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
8503 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
8504 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8505 CHECK_EQ(1, utf8buf[utf8_expected]);
8507 memset(buf, 0x1, sizeof(buf));
8508 memset(wbuf, 0x1, sizeof(wbuf));
8509 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8511 len = str->Write(wbuf);
8513 CHECK_EQ(0, strcmp("abcde", buf));
8514 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8515 CHECK_EQ(0, StrCmp16(answer1, wbuf));
8517 memset(buf, 0x1, sizeof(buf));
8518 memset(wbuf, 0x1, sizeof(wbuf));
8519 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
8521 len = str->Write(wbuf, 0, 4);
8523 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
8524 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8525 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8527 memset(buf, 0x1, sizeof(buf));
8528 memset(wbuf, 0x1, sizeof(wbuf));
8529 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
8531 len = str->Write(wbuf, 0, 5);
8533 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
8534 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8535 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8537 memset(buf, 0x1, sizeof(buf));
8538 memset(wbuf, 0x1, sizeof(wbuf));
8539 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
8541 len = str->Write(wbuf, 0, 6);
8543 CHECK_EQ(0, strcmp("abcde", buf));
8544 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8545 CHECK_EQ(0, StrCmp16(answer4, wbuf));
8547 memset(buf, 0x1, sizeof(buf));
8548 memset(wbuf, 0x1, sizeof(wbuf));
8549 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
8551 len = str->Write(wbuf, 4, -1);
8553 CHECK_EQ(0, strcmp("e", buf));
8554 uint16_t answer5[] = {'e', '\0'};
8555 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8557 memset(buf, 0x1, sizeof(buf));
8558 memset(wbuf, 0x1, sizeof(wbuf));
8559 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
8561 len = str->Write(wbuf, 4, 6);
8563 CHECK_EQ(0, strcmp("e", buf));
8564 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8566 memset(buf, 0x1, sizeof(buf));
8567 memset(wbuf, 0x1, sizeof(wbuf));
8568 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
8570 len = str->Write(wbuf, 4, 1);
8572 CHECK_EQ(0, strncmp("e\1", buf, 2));
8573 uint16_t answer6[] = {'e', 0x101};
8574 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8576 memset(buf, 0x1, sizeof(buf));
8577 memset(wbuf, 0x1, sizeof(wbuf));
8578 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
8580 len = str->Write(wbuf, 3, 1);
8582 CHECK_EQ(0, strncmp("d\1", buf, 2));
8583 uint16_t answer7[] = {'d', 0x101};
8584 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8586 memset(wbuf, 0x1, sizeof(wbuf));
8588 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8590 CHECK_EQ('X', wbuf[5]);
8591 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8592 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8593 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8594 CHECK_NE(0, StrCmp16(answer8b, wbuf));
8596 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8598 memset(buf, 0x1, sizeof(buf));
8600 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8603 String::NO_NULL_TERMINATION);
8605 CHECK_EQ('X', buf[5]);
8606 CHECK_EQ(0, strncmp("abcde", buf, 5));
8607 CHECK_NE(0, strcmp("abcde", buf));
8609 CHECK_EQ(0, strcmp("abcde", buf));
8611 memset(utf8buf, 0x1, sizeof(utf8buf));
8613 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8614 String::NO_NULL_TERMINATION);
8616 CHECK_EQ('X', utf8buf[8]);
8617 CHECK_EQ(5, charlen);
8618 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8619 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8621 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8623 memset(utf8buf, 0x1, sizeof(utf8buf));
8625 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8626 String::NO_NULL_TERMINATION);
8628 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8629 CHECK_EQ(5, charlen);
8631 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8633 memset(buf, 0x1, sizeof(buf));
8634 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8636 CHECK_EQ(0, strcmp("abc", buf));
8637 CHECK_EQ(0, buf[3]);
8638 CHECK_EQ(0, strcmp("def", buf + 4));
8640 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
8641 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
8642 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
8646 static void Utf16Helper(
8647 LocalContext& context, // NOLINT
8649 const char* lengths_name,
8651 Local<v8::Array> a =
8652 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8653 Local<v8::Array> alens =
8654 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8655 for (int i = 0; i < len; i++) {
8656 Local<v8::String> string =
8657 Local<v8::String>::Cast(a->Get(i));
8658 Local<v8::Number> expected_len =
8659 Local<v8::Number>::Cast(alens->Get(i));
8660 int length = GetUtf8Length(string);
8661 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8666 static uint16_t StringGet(Handle<String> str, int index) {
8667 i::Handle<i::String> istring =
8668 v8::Utils::OpenHandle(String::Cast(*str));
8669 return istring->Get(index);
8673 static void WriteUtf8Helper(
8674 LocalContext& context, // NOLINT
8676 const char* lengths_name,
8678 Local<v8::Array> b =
8679 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8680 Local<v8::Array> alens =
8681 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8684 for (int i = 0; i < len; i++) {
8685 Local<v8::String> string =
8686 Local<v8::String>::Cast(b->Get(i));
8687 Local<v8::Number> expected_len =
8688 Local<v8::Number>::Cast(alens->Get(i));
8689 int utf8_length = static_cast<int>(expected_len->Value());
8690 for (int j = utf8_length + 1; j >= 0; j--) {
8691 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8692 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8695 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8697 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8698 CHECK_GE(utf8_length + 1, utf8_written);
8699 CHECK_GE(utf8_length, utf8_written2);
8700 for (int k = 0; k < utf8_written2; k++) {
8701 CHECK_EQ(buffer[k], buffer2[k]);
8703 CHECK(nchars * 3 >= utf8_written - 1);
8704 CHECK(nchars <= utf8_written);
8705 if (j == utf8_length + 1) {
8706 CHECK_EQ(utf8_written2, utf8_length);
8707 CHECK_EQ(utf8_written2 + 1, utf8_written);
8709 CHECK_EQ(buffer[utf8_written], 42);
8710 if (j > utf8_length) {
8711 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8712 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8713 Handle<String> roundtrip = v8_str(buffer);
8714 CHECK(roundtrip->Equals(string));
8716 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8718 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8720 uint16_t trail = StringGet(string, nchars - 1);
8721 uint16_t lead = StringGet(string, nchars - 2);
8722 if (((lead & 0xfc00) == 0xd800) &&
8723 ((trail & 0xfc00) == 0xdc00)) {
8724 unsigned char u1 = buffer2[utf8_written2 - 4];
8725 unsigned char u2 = buffer2[utf8_written2 - 3];
8726 unsigned char u3 = buffer2[utf8_written2 - 2];
8727 unsigned char u4 = buffer2[utf8_written2 - 1];
8728 CHECK_EQ((u1 & 0xf8), 0xf0);
8729 CHECK_EQ((u2 & 0xc0), 0x80);
8730 CHECK_EQ((u3 & 0xc0), 0x80);
8731 CHECK_EQ((u4 & 0xc0), 0x80);
8732 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8733 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8734 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8735 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8736 CHECK_EQ((u1 & 0x3), c >> 18);
8744 THREADED_TEST(Utf16) {
8745 LocalContext context;
8746 v8::HandleScope scope(context->GetIsolate());
8748 "var pad = '01234567890123456789';"
8750 "var plens = [20, 3, 3];"
8751 "p.push('01234567890123456789');"
8752 "var lead = 0xd800;"
8753 "var trail = 0xdc00;"
8754 "p.push(String.fromCharCode(0xd800));"
8755 "p.push(String.fromCharCode(0xdc00));"
8760 "for (var i = 0; i < 3; i++) {"
8761 " p[1] = String.fromCharCode(lead++);"
8762 " for (var j = 0; j < 3; j++) {"
8763 " p[2] = String.fromCharCode(trail++);"
8764 " a.push(p[i] + p[j]);"
8765 " b.push(p[i] + p[j]);"
8766 " c.push(p[i] + p[j]);"
8767 " alens.push(plens[i] + plens[j]);"
8770 "alens[5] -= 2;" // Here the surrogate pairs match up.
8775 "for (var m = 0; m < 9; m++) {"
8776 " for (var n = 0; n < 9; n++) {"
8777 " a2.push(a[m] + a[n]);"
8778 " b2.push(b[m] + b[n]);"
8779 " var newc = 'x' + c[m] + c[n] + 'y';"
8780 " c2.push(newc.substring(1, newc.length - 1));"
8781 " var utf = alens[m] + alens[n];" // And here.
8782 // The 'n's that start with 0xdc.. are 6-8
8783 // The 'm's that end with 0xd8.. are 1, 4 and 7
8784 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8785 " a2lens.push(utf);"
8788 Utf16Helper(context, "a", "alens", 9);
8789 Utf16Helper(context, "a2", "a2lens", 81);
8790 WriteUtf8Helper(context, "b", "alens", 9);
8791 WriteUtf8Helper(context, "b2", "a2lens", 81);
8792 WriteUtf8Helper(context, "c2", "a2lens", 81);
8796 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8797 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8798 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8799 return *is1 == *is2;
8802 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8804 Handle<String> symbol1 =
8805 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8806 Handle<String> symbol2 =
8807 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8808 CHECK(SameSymbol(symbol1, symbol2));
8812 THREADED_TEST(Utf16Symbol) {
8813 LocalContext context;
8814 v8::HandleScope scope(context->GetIsolate());
8816 Handle<String> symbol1 = v8::String::NewFromUtf8(
8817 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8818 Handle<String> symbol2 = v8::String::NewFromUtf8(
8819 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8820 CHECK(SameSymbol(symbol1, symbol2));
8822 SameSymbolHelper(context->GetIsolate(),
8823 "\360\220\220\205", // 4 byte encoding.
8824 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8825 SameSymbolHelper(context->GetIsolate(),
8826 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8827 "\360\220\220\206"); // 4 byte encoding.
8828 SameSymbolHelper(context->GetIsolate(),
8829 "x\360\220\220\205", // 4 byte encoding.
8830 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8831 SameSymbolHelper(context->GetIsolate(),
8832 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8833 "x\360\220\220\206"); // 4 byte encoding.
8835 "var sym0 = 'benedictus';"
8836 "var sym0b = 'S\303\270ren';"
8837 "var sym1 = '\355\240\201\355\260\207';"
8838 "var sym2 = '\360\220\220\210';"
8839 "var sym3 = 'x\355\240\201\355\260\207';"
8840 "var sym4 = 'x\360\220\220\210';"
8841 "if (sym1.length != 2) throw sym1;"
8842 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8843 "if (sym2.length != 2) throw sym2;"
8844 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8845 "if (sym3.length != 3) throw sym3;"
8846 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8847 "if (sym4.length != 3) throw sym4;"
8848 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8849 Handle<String> sym0 = v8::String::NewFromUtf8(
8850 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8851 Handle<String> sym0b = v8::String::NewFromUtf8(
8852 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8853 Handle<String> sym1 =
8854 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8855 v8::String::kInternalizedString);
8856 Handle<String> sym2 =
8857 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8858 v8::String::kInternalizedString);
8859 Handle<String> sym3 = v8::String::NewFromUtf8(
8860 context->GetIsolate(), "x\355\240\201\355\260\207",
8861 v8::String::kInternalizedString);
8862 Handle<String> sym4 =
8863 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8864 v8::String::kInternalizedString);
8865 v8::Local<v8::Object> global = context->Global();
8866 Local<Value> s0 = global->Get(v8_str("sym0"));
8867 Local<Value> s0b = global->Get(v8_str("sym0b"));
8868 Local<Value> s1 = global->Get(v8_str("sym1"));
8869 Local<Value> s2 = global->Get(v8_str("sym2"));
8870 Local<Value> s3 = global->Get(v8_str("sym3"));
8871 Local<Value> s4 = global->Get(v8_str("sym4"));
8872 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8873 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8874 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8875 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8876 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8877 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8881 THREADED_TEST(ToArrayIndex) {
8882 LocalContext context;
8883 v8::Isolate* isolate = context->GetIsolate();
8884 v8::HandleScope scope(isolate);
8886 v8::Handle<String> str = v8_str("42");
8887 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8888 CHECK(!index.IsEmpty());
8889 CHECK_EQ(42.0, index->Uint32Value());
8890 str = v8_str("42asdf");
8891 index = str->ToArrayIndex();
8892 CHECK(index.IsEmpty());
8893 str = v8_str("-42");
8894 index = str->ToArrayIndex();
8895 CHECK(index.IsEmpty());
8896 str = v8_str("4294967295");
8897 index = str->ToArrayIndex();
8898 CHECK(!index.IsEmpty());
8899 CHECK_EQ(4294967295.0, index->Uint32Value());
8900 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8901 index = num->ToArrayIndex();
8902 CHECK(!index.IsEmpty());
8903 CHECK_EQ(1.0, index->Uint32Value());
8904 num = v8::Number::New(isolate, -1);
8905 index = num->ToArrayIndex();
8906 CHECK(index.IsEmpty());
8907 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8908 index = obj->ToArrayIndex();
8909 CHECK(index.IsEmpty());
8913 THREADED_TEST(ErrorConstruction) {
8914 LocalContext context;
8915 v8::HandleScope scope(context->GetIsolate());
8917 v8::Handle<String> foo = v8_str("foo");
8918 v8::Handle<String> message = v8_str("message");
8919 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8920 CHECK(range_error->IsObject());
8921 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8922 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8923 CHECK(reference_error->IsObject());
8924 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8925 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8926 CHECK(syntax_error->IsObject());
8927 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8928 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8929 CHECK(type_error->IsObject());
8930 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8931 v8::Handle<Value> error = v8::Exception::Error(foo);
8932 CHECK(error->IsObject());
8933 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8937 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
8938 ApiTestFuzzer::Fuzz();
8939 v8::Handle<String> foo = v8_str("foo");
8940 v8::Handle<String> message = v8_str("message");
8941 v8::Handle<Value> error = v8::Exception::Error(foo);
8942 CHECK(error->IsObject());
8943 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8944 info.GetIsolate()->ThrowException(error);
8945 info.GetReturnValue().SetUndefined();
8949 THREADED_TEST(ExceptionCreateMessage) {
8950 LocalContext context;
8951 v8::HandleScope scope(context->GetIsolate());
8952 v8::Handle<String> foo_str = v8_str("foo");
8953 v8::Handle<String> message_str = v8_str("message");
8955 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
8957 Local<v8::FunctionTemplate> fun =
8958 v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
8959 v8::Local<v8::Object> global = context->Global();
8960 global->Set(v8_str("throwV8Exception"), fun->GetFunction());
8965 " throwV8Exception();\n"
8968 CHECK(try_catch.HasCaught());
8970 v8::Handle<v8::Value> error = try_catch.Exception();
8971 CHECK(error->IsObject());
8972 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
8974 v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
8975 CHECK(!message.IsEmpty());
8976 CHECK_EQ(2, message->GetLineNumber());
8977 CHECK_EQ(2, message->GetStartColumn());
8979 v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
8980 CHECK(!stackTrace.IsEmpty());
8981 CHECK_EQ(2, stackTrace->GetFrameCount());
8983 stackTrace = v8::Exception::GetStackTrace(error);
8984 CHECK(!stackTrace.IsEmpty());
8985 CHECK_EQ(2, stackTrace->GetFrameCount());
8987 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
8989 // Now check message location when SetCaptureStackTraceForUncaughtExceptions
8995 " return throwV8Exception();\n"
8998 CHECK(try_catch.HasCaught());
9000 error = try_catch.Exception();
9001 CHECK(error->IsObject());
9002 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
9004 message = v8::Exception::CreateMessage(error);
9005 CHECK(!message.IsEmpty());
9006 CHECK_EQ(2, message->GetLineNumber());
9007 CHECK_EQ(9, message->GetStartColumn());
9009 // Should be empty stack trace.
9010 stackTrace = message->GetStackTrace();
9011 CHECK(stackTrace.IsEmpty());
9012 CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
9016 static void YGetter(Local<String> name,
9017 const v8::PropertyCallbackInfo<v8::Value>& info) {
9018 ApiTestFuzzer::Fuzz();
9019 info.GetReturnValue().Set(v8_num(10));
9023 static void YSetter(Local<String> name,
9025 const v8::PropertyCallbackInfo<void>& info) {
9026 Local<Object> this_obj = Local<Object>::Cast(info.This());
9027 if (this_obj->Has(name)) this_obj->Delete(name);
9028 this_obj->Set(name, value);
9032 THREADED_TEST(DeleteAccessor) {
9033 v8::Isolate* isolate = CcTest::isolate();
9034 v8::HandleScope scope(isolate);
9035 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
9036 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
9037 LocalContext context;
9038 v8::Handle<v8::Object> holder = obj->NewInstance();
9039 context->Global()->Set(v8_str("holder"), holder);
9040 v8::Handle<Value> result = CompileRun(
9041 "holder.y = 11; holder.y = 12; holder.y");
9042 CHECK_EQ(12, result->Uint32Value());
9046 THREADED_TEST(TypeSwitch) {
9047 v8::Isolate* isolate = CcTest::isolate();
9048 v8::HandleScope scope(isolate);
9049 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
9050 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
9051 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
9052 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
9053 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
9054 LocalContext context;
9055 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
9056 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
9057 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
9058 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
9059 for (int i = 0; i < 10; i++) {
9060 CHECK_EQ(0, type_switch->match(obj0));
9061 CHECK_EQ(1, type_switch->match(obj1));
9062 CHECK_EQ(2, type_switch->match(obj2));
9063 CHECK_EQ(3, type_switch->match(obj3));
9064 CHECK_EQ(3, type_switch->match(obj3));
9065 CHECK_EQ(2, type_switch->match(obj2));
9066 CHECK_EQ(1, type_switch->match(obj1));
9067 CHECK_EQ(0, type_switch->match(obj0));
9072 static int trouble_nesting = 0;
9073 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
9074 ApiTestFuzzer::Fuzz();
9077 // Call a JS function that throws an uncaught exception.
9078 Local<v8::Object> arg_this =
9079 args.GetIsolate()->GetCurrentContext()->Global();
9080 Local<Value> trouble_callee = (trouble_nesting == 3) ?
9081 arg_this->Get(v8_str("trouble_callee")) :
9082 arg_this->Get(v8_str("trouble_caller"));
9083 CHECK(trouble_callee->IsFunction());
9084 args.GetReturnValue().Set(
9085 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
9089 static int report_count = 0;
9090 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
9091 v8::Handle<Value>) {
9096 // Counts uncaught exceptions, but other tests running in parallel
9097 // also have uncaught exceptions.
9098 TEST(ApiUncaughtException) {
9101 v8::Isolate* isolate = env->GetIsolate();
9102 v8::HandleScope scope(isolate);
9103 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
9105 Local<v8::FunctionTemplate> fun =
9106 v8::FunctionTemplate::New(isolate, TroubleCallback);
9107 v8::Local<v8::Object> global = env->Global();
9108 global->Set(v8_str("trouble"), fun->GetFunction());
9111 "function trouble_callee() {"
9115 "function trouble_caller() {"
9118 Local<Value> trouble = global->Get(v8_str("trouble"));
9119 CHECK(trouble->IsFunction());
9120 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
9121 CHECK(trouble_callee->IsFunction());
9122 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
9123 CHECK(trouble_caller->IsFunction());
9124 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
9125 CHECK_EQ(1, report_count);
9126 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9130 TEST(ApiUncaughtExceptionInObjectObserve) {
9131 v8::internal::FLAG_stack_size = 150;
9134 v8::Isolate* isolate = env->GetIsolate();
9135 v8::HandleScope scope(isolate);
9136 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
9139 "var observe_count = 0;"
9140 "function observer1() { ++observe_count; };"
9141 "function observer2() { ++observe_count; };"
9142 "function observer_throws() { throw new Error(); };"
9143 "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
9144 "Object.observe(obj, observer_throws.bind());"
9145 "Object.observe(obj, observer1);"
9146 "Object.observe(obj, stack_overflow);"
9147 "Object.observe(obj, observer2);"
9148 "Object.observe(obj, observer_throws.bind());"
9149 "obj.foo = 'bar';");
9150 CHECK_EQ(3, report_count);
9151 ExpectInt32("observe_count", 2);
9152 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
9156 static const char* script_resource_name = "ExceptionInNativeScript.js";
9157 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
9158 v8::Handle<Value>) {
9159 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
9160 CHECK(!name_val.IsEmpty() && name_val->IsString());
9161 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
9162 CHECK_EQ(script_resource_name, *name);
9163 CHECK_EQ(3, message->GetLineNumber());
9164 v8::String::Utf8Value source_line(message->GetSourceLine());
9165 CHECK_EQ(" new o.foo();", *source_line);
9169 TEST(ExceptionInNativeScript) {
9171 v8::Isolate* isolate = env->GetIsolate();
9172 v8::HandleScope scope(isolate);
9173 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
9175 Local<v8::FunctionTemplate> fun =
9176 v8::FunctionTemplate::New(isolate, TroubleCallback);
9177 v8::Local<v8::Object> global = env->Global();
9178 global->Set(v8_str("trouble"), fun->GetFunction());
9180 CompileRunWithOrigin(
9181 "function trouble() {\n"
9185 script_resource_name);
9186 Local<Value> trouble = global->Get(v8_str("trouble"));
9187 CHECK(trouble->IsFunction());
9188 Function::Cast(*trouble)->Call(global, 0, NULL);
9189 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
9193 TEST(CompilationErrorUsingTryCatchHandler) {
9195 v8::HandleScope scope(env->GetIsolate());
9196 v8::TryCatch try_catch;
9197 v8_compile("This doesn't &*&@#$&*^ compile.");
9198 CHECK_NE(NULL, *try_catch.Exception());
9199 CHECK(try_catch.HasCaught());
9203 TEST(TryCatchFinallyUsingTryCatchHandler) {
9205 v8::HandleScope scope(env->GetIsolate());
9206 v8::TryCatch try_catch;
9207 CompileRun("try { throw ''; } catch (e) {}");
9208 CHECK(!try_catch.HasCaught());
9209 CompileRun("try { throw ''; } finally {}");
9210 CHECK(try_catch.HasCaught());
9214 "try { throw ''; } finally { return; }"
9216 CHECK(!try_catch.HasCaught());
9219 " { try { throw ''; } finally { throw 0; }"
9221 CHECK(try_catch.HasCaught());
9225 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
9226 v8::HandleScope scope(args.GetIsolate());
9227 CompileRun(args[0]->ToString(args.GetIsolate()));
9231 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
9232 v8::Isolate* isolate = CcTest::isolate();
9233 v8::HandleScope scope(isolate);
9234 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
9235 templ->Set(v8_str("CEvaluate"),
9236 v8::FunctionTemplate::New(isolate, CEvaluate));
9237 LocalContext context(0, templ);
9238 v8::TryCatch try_catch;
9240 " CEvaluate('throw 1;');"
9243 CHECK(try_catch.HasCaught());
9244 CHECK(!try_catch.Message().IsEmpty());
9245 String::Utf8Value exception_value(try_catch.Exception());
9246 CHECK_EQ(*exception_value, "1");
9249 " CEvaluate('throw 1;');"
9253 CHECK(try_catch.HasCaught());
9254 CHECK(!try_catch.Message().IsEmpty());
9255 String::Utf8Value finally_exception_value(try_catch.Exception());
9256 CHECK_EQ(*finally_exception_value, "2");
9260 // For use within the TestSecurityHandler() test.
9261 static bool g_security_callback_result = false;
9262 static bool NamedSecurityTestCallback(Local<v8::Object> global,
9264 v8::AccessType type,
9265 Local<Value> data) {
9267 // Always allow read access.
9268 if (type == v8::ACCESS_GET)
9271 // Sometimes allow other access.
9272 return g_security_callback_result;
9276 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
9278 v8::AccessType type,
9279 Local<Value> data) {
9281 // Always allow read access.
9282 if (type == v8::ACCESS_GET)
9285 // Sometimes allow other access.
9286 return g_security_callback_result;
9290 // SecurityHandler can't be run twice
9291 TEST(SecurityHandler) {
9292 v8::Isolate* isolate = CcTest::isolate();
9293 v8::HandleScope scope0(isolate);
9294 v8::Handle<v8::ObjectTemplate> global_template =
9295 v8::ObjectTemplate::New(isolate);
9296 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
9297 IndexedSecurityTestCallback);
9298 // Create an environment
9299 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
9302 v8::Handle<v8::Object> global0 = context0->Global();
9303 v8::Handle<Script> script0 = v8_compile("foo = 111");
9305 global0->Set(v8_str("0"), v8_num(999));
9306 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
9307 CHECK_EQ(111, foo0->Int32Value());
9308 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
9309 CHECK_EQ(999, z0->Int32Value());
9311 // Create another environment, should fail security checks.
9312 v8::HandleScope scope1(isolate);
9314 v8::Handle<Context> context1 =
9315 Context::New(isolate, NULL, global_template);
9318 v8::Handle<v8::Object> global1 = context1->Global();
9319 global1->Set(v8_str("othercontext"), global0);
9320 // This set will fail the security check.
9321 v8::Handle<Script> script1 =
9322 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
9324 // This read will pass the security check.
9325 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
9326 CHECK_EQ(111, foo1->Int32Value());
9327 // This read will pass the security check.
9328 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
9329 CHECK_EQ(999, z1->Int32Value());
9331 // Create another environment, should pass security checks.
9332 { g_security_callback_result = true; // allow security handler to pass.
9333 v8::HandleScope scope2(isolate);
9334 LocalContext context2;
9335 v8::Handle<v8::Object> global2 = context2->Global();
9336 global2->Set(v8_str("othercontext"), global0);
9337 v8::Handle<Script> script2 =
9338 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
9340 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
9341 CHECK_EQ(333, foo2->Int32Value());
9342 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
9343 CHECK_EQ(888, z2->Int32Value());
9351 THREADED_TEST(SecurityChecks) {
9353 v8::HandleScope handle_scope(env1->GetIsolate());
9354 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9356 Local<Value> foo = v8_str("foo");
9357 Local<Value> bar = v8_str("bar");
9359 // Set to the same domain.
9360 env1->SetSecurityToken(foo);
9362 // Create a function in env1.
9363 CompileRun("spy=function(){return spy;}");
9364 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
9365 CHECK(spy->IsFunction());
9367 // Create another function accessing global objects.
9368 CompileRun("spy2=function(){return new this.Array();}");
9369 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
9370 CHECK(spy2->IsFunction());
9372 // Switch to env2 in the same domain and invoke spy on env2.
9374 env2->SetSecurityToken(foo);
9376 Context::Scope scope_env2(env2);
9377 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
9378 CHECK(result->IsFunction());
9382 env2->SetSecurityToken(bar);
9383 Context::Scope scope_env2(env2);
9385 // Call cross_domain_call, it should throw an exception
9386 v8::TryCatch try_catch;
9387 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
9388 CHECK(try_catch.HasCaught());
9393 // Regression test case for issue 1183439.
9394 THREADED_TEST(SecurityChecksForPrototypeChain) {
9395 LocalContext current;
9396 v8::HandleScope scope(current->GetIsolate());
9397 v8::Handle<Context> other = Context::New(current->GetIsolate());
9399 // Change context to be able to get to the Object function in the
9400 // other context without hitting the security checks.
9401 v8::Local<Value> other_object;
9402 { Context::Scope scope(other);
9403 other_object = other->Global()->Get(v8_str("Object"));
9404 other->Global()->Set(v8_num(42), v8_num(87));
9407 current->Global()->Set(v8_str("other"), other->Global());
9408 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
9410 // Make sure the security check fails here and we get an undefined
9411 // result instead of getting the Object function. Repeat in a loop
9412 // to make sure to exercise the IC code.
9413 v8::Local<Script> access_other0 = v8_compile("other.Object");
9414 v8::Local<Script> access_other1 = v8_compile("other[42]");
9415 for (int i = 0; i < 5; i++) {
9416 CHECK(access_other0->Run().IsEmpty());
9417 CHECK(access_other1->Run().IsEmpty());
9420 // Create an object that has 'other' in its prototype chain and make
9421 // sure we cannot access the Object function indirectly through
9422 // that. Repeat in a loop to make sure to exercise the IC code.
9423 v8_compile("function F() { };"
9424 "F.prototype = other;"
9425 "var f = new F();")->Run();
9426 v8::Local<Script> access_f0 = v8_compile("f.Object");
9427 v8::Local<Script> access_f1 = v8_compile("f[42]");
9428 for (int j = 0; j < 5; j++) {
9429 CHECK(access_f0->Run().IsEmpty());
9430 CHECK(access_f1->Run().IsEmpty());
9433 // Now it gets hairy: Set the prototype for the other global object
9434 // to be the current global object. The prototype chain for 'f' now
9435 // goes through 'other' but ends up in the current global object.
9436 { Context::Scope scope(other);
9437 other->Global()->Set(v8_str("__proto__"), current->Global());
9439 // Set a named and an index property on the current global
9440 // object. To force the lookup to go through the other global object,
9441 // the properties must not exist in the other global object.
9442 current->Global()->Set(v8_str("foo"), v8_num(100));
9443 current->Global()->Set(v8_num(99), v8_num(101));
9444 // Try to read the properties from f and make sure that the access
9445 // gets stopped by the security checks on the other global object.
9446 Local<Script> access_f2 = v8_compile("f.foo");
9447 Local<Script> access_f3 = v8_compile("f[99]");
9448 for (int k = 0; k < 5; k++) {
9449 CHECK(access_f2->Run().IsEmpty());
9450 CHECK(access_f3->Run().IsEmpty());
9455 static bool named_security_check_with_gc_called;
9457 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
9459 v8::AccessType type,
9460 Local<Value> data) {
9461 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
9462 named_security_check_with_gc_called = true;
9467 static bool indexed_security_check_with_gc_called;
9469 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
9471 v8::AccessType type,
9472 Local<Value> data) {
9473 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
9474 indexed_security_check_with_gc_called = true;
9479 TEST(SecurityTestGCAllowed) {
9480 v8::Isolate* isolate = CcTest::isolate();
9481 v8::HandleScope handle_scope(isolate);
9482 v8::Handle<v8::ObjectTemplate> object_template =
9483 v8::ObjectTemplate::New(isolate);
9484 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
9485 IndexedSecurityTestCallbackWithGC);
9487 v8::Handle<Context> context = Context::New(isolate);
9488 v8::Context::Scope context_scope(context);
9490 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
9492 named_security_check_with_gc_called = false;
9493 CompileRun("obj.foo = new String(1001);");
9494 CHECK(named_security_check_with_gc_called);
9496 indexed_security_check_with_gc_called = false;
9497 CompileRun("obj[0] = new String(1002);");
9498 CHECK(indexed_security_check_with_gc_called);
9500 named_security_check_with_gc_called = false;
9501 CHECK(CompileRun("obj.foo")->ToString(isolate)->Equals(v8_str("1001")));
9502 CHECK(named_security_check_with_gc_called);
9504 indexed_security_check_with_gc_called = false;
9505 CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
9506 CHECK(indexed_security_check_with_gc_called);
9510 THREADED_TEST(CrossDomainDelete) {
9512 v8::HandleScope handle_scope(env1->GetIsolate());
9513 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9515 Local<Value> foo = v8_str("foo");
9516 Local<Value> bar = v8_str("bar");
9518 // Set to the same domain.
9519 env1->SetSecurityToken(foo);
9520 env2->SetSecurityToken(foo);
9522 env1->Global()->Set(v8_str("prop"), v8_num(3));
9523 env2->Global()->Set(v8_str("env1"), env1->Global());
9525 // Change env2 to a different domain and delete env1.prop.
9526 env2->SetSecurityToken(bar);
9528 Context::Scope scope_env2(env2);
9529 Local<Value> result =
9530 CompileRun("delete env1.prop");
9531 CHECK(result.IsEmpty());
9534 // Check that env1.prop still exists.
9535 Local<Value> v = env1->Global()->Get(v8_str("prop"));
9536 CHECK(v->IsNumber());
9537 CHECK_EQ(3, v->Int32Value());
9541 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
9543 v8::HandleScope handle_scope(env1->GetIsolate());
9544 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9546 Local<Value> foo = v8_str("foo");
9547 Local<Value> bar = v8_str("bar");
9549 // Set to the same domain.
9550 env1->SetSecurityToken(foo);
9551 env2->SetSecurityToken(foo);
9553 env1->Global()->Set(v8_str("prop"), v8_num(3));
9554 env2->Global()->Set(v8_str("env1"), env1->Global());
9556 // env1.prop is enumerable in env2.
9557 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9559 Context::Scope scope_env2(env2);
9560 Local<Value> result = CompileRun(test);
9561 CHECK(result->IsTrue());
9564 // Change env2 to a different domain and test again.
9565 env2->SetSecurityToken(bar);
9567 Context::Scope scope_env2(env2);
9568 Local<Value> result = CompileRun(test);
9569 CHECK(result.IsEmpty());
9574 THREADED_TEST(CrossDomainForIn) {
9576 v8::HandleScope handle_scope(env1->GetIsolate());
9577 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9579 Local<Value> foo = v8_str("foo");
9580 Local<Value> bar = v8_str("bar");
9582 // Set to the same domain.
9583 env1->SetSecurityToken(foo);
9584 env2->SetSecurityToken(foo);
9586 env1->Global()->Set(v8_str("prop"), v8_num(3));
9587 env2->Global()->Set(v8_str("env1"), env1->Global());
9589 // Change env2 to a different domain and set env1's global object
9590 // as the __proto__ of an object in env2 and enumerate properties
9591 // in for-in. It shouldn't enumerate properties on env1's global
9593 env2->SetSecurityToken(bar);
9595 Context::Scope scope_env2(env2);
9596 Local<Value> result = CompileRun(
9598 " var obj = { '__proto__': env1 };"
9600 " for (var p in obj) {"
9601 " if (p == 'prop') return false;"
9608 CHECK(result->IsTrue());
9613 TEST(ContextDetachGlobal) {
9615 v8::HandleScope handle_scope(env1->GetIsolate());
9616 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9618 Local<v8::Object> global1 = env1->Global();
9620 Local<Value> foo = v8_str("foo");
9622 // Set to the same domain.
9623 env1->SetSecurityToken(foo);
9624 env2->SetSecurityToken(foo);
9629 // Create a function in env2 and add a reference to it in env1.
9630 Local<v8::Object> global2 = env2->Global();
9631 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
9632 CompileRun("function getProp() {return prop;}");
9634 env1->Global()->Set(v8_str("getProp"),
9635 global2->Get(v8_str("getProp")));
9637 // Detach env2's global, and reuse the global object of env2
9639 env2->DetachGlobal();
9641 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9643 v8::Handle<v8::ObjectTemplate>(),
9645 env3->SetSecurityToken(v8_str("bar"));
9648 Local<v8::Object> global3 = env3->Global();
9649 CHECK_EQ(global2, global3);
9650 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
9651 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
9652 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
9653 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
9656 // Call getProp in env1, and it should return the value 1
9658 Local<Value> get_prop = global1->Get(v8_str("getProp"));
9659 CHECK(get_prop->IsFunction());
9660 v8::TryCatch try_catch;
9661 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
9662 CHECK(!try_catch.HasCaught());
9663 CHECK_EQ(1, r->Int32Value());
9666 // Check that env3 is not accessible from env1
9668 Local<Value> r = global3->Get(v8_str("prop2"));
9674 TEST(DetachGlobal) {
9676 v8::HandleScope scope(env1->GetIsolate());
9678 // Create second environment.
9679 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9681 Local<Value> foo = v8_str("foo");
9683 // Set same security token for env1 and env2.
9684 env1->SetSecurityToken(foo);
9685 env2->SetSecurityToken(foo);
9687 // Create a property on the global object in env2.
9689 v8::Context::Scope scope(env2);
9690 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
9693 // Create a reference to env2 global from env1 global.
9694 env1->Global()->Set(v8_str("other"), env2->Global());
9696 // Check that we have access to other.p in env2 from env1.
9697 Local<Value> result = CompileRun("other.p");
9698 CHECK(result->IsInt32());
9699 CHECK_EQ(42, result->Int32Value());
9701 // Hold on to global from env2 and detach global from env2.
9702 Local<v8::Object> global2 = env2->Global();
9703 env2->DetachGlobal();
9705 // Check that the global has been detached. No other.p property can
9707 result = CompileRun("other.p");
9708 CHECK(result.IsEmpty());
9710 // Reuse global2 for env3.
9711 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9713 v8::Handle<v8::ObjectTemplate>(),
9715 CHECK_EQ(global2, env3->Global());
9717 // Start by using the same security token for env3 as for env1 and env2.
9718 env3->SetSecurityToken(foo);
9720 // Create a property on the global object in env3.
9722 v8::Context::Scope scope(env3);
9723 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
9726 // Check that other.p is now the property in env3 and that we have access.
9727 result = CompileRun("other.p");
9728 CHECK(result->IsInt32());
9729 CHECK_EQ(24, result->Int32Value());
9731 // Change security token for env3 to something different from env1 and env2.
9732 env3->SetSecurityToken(v8_str("bar"));
9734 // Check that we do not have access to other.p in env1. |other| is now
9735 // the global object for env3 which has a different security token,
9736 // so access should be blocked.
9737 result = CompileRun("other.p");
9738 CHECK(result.IsEmpty());
9742 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9743 info.GetReturnValue().Set(
9744 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
9748 TEST(DetachedAccesses) {
9750 v8::HandleScope scope(env1->GetIsolate());
9752 // Create second environment.
9753 Local<ObjectTemplate> inner_global_template =
9754 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9755 inner_global_template ->SetAccessorProperty(
9756 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9757 v8::Local<Context> env2 =
9758 Context::New(env1->GetIsolate(), NULL, inner_global_template);
9760 Local<Value> foo = v8_str("foo");
9762 // Set same security token for env1 and env2.
9763 env1->SetSecurityToken(foo);
9764 env2->SetSecurityToken(foo);
9766 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9769 v8::Context::Scope scope(env2);
9770 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9772 "function bound_x() { return x; }"
9773 "function get_x() { return this.x; }"
9774 "function get_x_w() { return (function() {return this.x;})(); }");
9775 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9776 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9777 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9778 env1->Global()->Set(
9780 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9783 Local<Object> env2_global = env2->Global();
9784 env2_global->TurnOnAccessCheck();
9785 env2->DetachGlobal();
9787 Local<Value> result;
9788 result = CompileRun("bound_x()");
9789 CHECK_EQ(v8_str("env2_x"), result);
9790 result = CompileRun("get_x()");
9791 CHECK(result.IsEmpty());
9792 result = CompileRun("get_x_w()");
9793 CHECK(result.IsEmpty());
9794 result = CompileRun("this_x()");
9795 CHECK_EQ(v8_str("env2_x"), result);
9797 // Reattach env2's proxy
9798 env2 = Context::New(env1->GetIsolate(),
9800 v8::Handle<v8::ObjectTemplate>(),
9802 env2->SetSecurityToken(foo);
9804 v8::Context::Scope scope(env2);
9805 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9806 env2->Global()->Set(v8_str("env1"), env1->Global());
9807 result = CompileRun(
9809 "for (var i = 0; i < 4; i++ ) {"
9810 " results.push(env1.bound_x());"
9811 " results.push(env1.get_x());"
9812 " results.push(env1.get_x_w());"
9813 " results.push(env1.this_x());"
9816 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9817 CHECK_EQ(16, results->Length());
9818 for (int i = 0; i < 16; i += 4) {
9819 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9820 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9821 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9822 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9826 result = CompileRun(
9828 "for (var i = 0; i < 4; i++ ) {"
9829 " results.push(bound_x());"
9830 " results.push(get_x());"
9831 " results.push(get_x_w());"
9832 " results.push(this_x());"
9835 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9836 CHECK_EQ(16, results->Length());
9837 for (int i = 0; i < 16; i += 4) {
9838 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9839 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9840 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9841 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9844 result = CompileRun(
9846 "for (var i = 0; i < 4; i++ ) {"
9847 " results.push(this.bound_x());"
9848 " results.push(this.get_x());"
9849 " results.push(this.get_x_w());"
9850 " results.push(this.this_x());"
9853 results = Local<v8::Array>::Cast(result);
9854 CHECK_EQ(16, results->Length());
9855 for (int i = 0; i < 16; i += 4) {
9856 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9857 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9858 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9859 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9864 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9865 static bool NamedAccessBlocker(Local<v8::Object> global,
9867 v8::AccessType type,
9868 Local<Value> data) {
9869 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9870 allowed_access_type[type];
9874 static bool IndexedAccessBlocker(Local<v8::Object> global,
9876 v8::AccessType type,
9877 Local<Value> data) {
9878 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9879 allowed_access_type[type];
9883 static int g_echo_value = -1;
9886 static void EchoGetter(
9888 const v8::PropertyCallbackInfo<v8::Value>& info) {
9889 info.GetReturnValue().Set(v8_num(g_echo_value));
9893 static void EchoSetter(Local<String> name,
9895 const v8::PropertyCallbackInfo<void>&) {
9896 if (value->IsNumber())
9897 g_echo_value = value->Int32Value();
9901 static void UnreachableGetter(
9903 const v8::PropertyCallbackInfo<v8::Value>& info) {
9904 CHECK(false); // This function should not be called..
9908 static void UnreachableSetter(Local<String>,
9910 const v8::PropertyCallbackInfo<void>&) {
9911 CHECK(false); // This function should nto be called.
9915 static void UnreachableFunction(
9916 const v8::FunctionCallbackInfo<v8::Value>& info) {
9917 CHECK(false); // This function should not be called..
9921 TEST(AccessControl) {
9922 v8::Isolate* isolate = CcTest::isolate();
9923 v8::HandleScope handle_scope(isolate);
9924 v8::Handle<v8::ObjectTemplate> global_template =
9925 v8::ObjectTemplate::New(isolate);
9927 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9928 IndexedAccessBlocker);
9930 // Add an accessor accessible by cross-domain JS code.
9931 global_template->SetAccessor(
9932 v8_str("accessible_prop"),
9933 EchoGetter, EchoSetter,
9934 v8::Handle<Value>(),
9935 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9938 // Add an accessor that is not accessible by cross-domain JS code.
9939 global_template->SetAccessor(v8_str("blocked_prop"),
9940 UnreachableGetter, UnreachableSetter,
9941 v8::Handle<Value>(),
9944 global_template->SetAccessorProperty(
9945 v8_str("blocked_js_prop"),
9946 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9947 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9951 // Create an environment
9952 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9955 v8::Handle<v8::Object> global0 = context0->Global();
9957 // Define a property with JS getter and setter.
9959 "function getter() { return 'getter'; };\n"
9960 "function setter() { return 'setter'; }\n"
9961 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9963 Local<Value> getter = global0->Get(v8_str("getter"));
9964 Local<Value> setter = global0->Get(v8_str("setter"));
9966 // And define normal element.
9967 global0->Set(239, v8_str("239"));
9969 // Define an element with JS getter and setter.
9971 "function el_getter() { return 'el_getter'; };\n"
9972 "function el_setter() { return 'el_setter'; };\n"
9973 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9975 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9976 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9978 v8::HandleScope scope1(isolate);
9980 v8::Local<Context> context1 = Context::New(isolate);
9983 v8::Handle<v8::Object> global1 = context1->Global();
9984 global1->Set(v8_str("other"), global0);
9986 // Access blocked property.
9987 CompileRun("other.blocked_prop = 1");
9989 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9990 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9993 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9995 // Access blocked element.
9996 CHECK(CompileRun("other[239] = 1").IsEmpty());
9998 CHECK(CompileRun("other[239]").IsEmpty());
9999 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
10000 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
10002 // Enable ACCESS_HAS
10003 allowed_access_type[v8::ACCESS_HAS] = true;
10004 CHECK(CompileRun("other[239]").IsEmpty());
10005 // ... and now we can get the descriptor...
10006 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
10008 // ... and enumerate the property.
10009 ExpectTrue("propertyIsEnumerable.call(other, '239')");
10010 allowed_access_type[v8::ACCESS_HAS] = false;
10012 // Access a property with JS accessor.
10013 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
10015 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
10016 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
10019 // Enable both ACCESS_HAS and ACCESS_GET.
10020 allowed_access_type[v8::ACCESS_HAS] = true;
10021 allowed_access_type[v8::ACCESS_GET] = true;
10023 ExpectString("other.js_accessor_p", "getter");
10025 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
10027 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
10029 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
10031 allowed_access_type[v8::ACCESS_HAS] = false;
10032 allowed_access_type[v8::ACCESS_GET] = false;
10034 // Access an element with JS accessor.
10035 CHECK(CompileRun("other[42] = 2").IsEmpty());
10037 CHECK(CompileRun("other[42]").IsEmpty());
10038 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
10040 // Enable both ACCESS_HAS and ACCESS_GET.
10041 allowed_access_type[v8::ACCESS_HAS] = true;
10042 allowed_access_type[v8::ACCESS_GET] = true;
10044 ExpectString("other[42]", "el_getter");
10045 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
10046 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
10047 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
10049 allowed_access_type[v8::ACCESS_HAS] = false;
10050 allowed_access_type[v8::ACCESS_GET] = false;
10052 v8::Handle<Value> value;
10054 // Access accessible property
10055 value = CompileRun("other.accessible_prop = 3");
10056 CHECK(value->IsNumber());
10057 CHECK_EQ(3, value->Int32Value());
10058 CHECK_EQ(3, g_echo_value);
10060 value = CompileRun("other.accessible_prop");
10061 CHECK(value->IsNumber());
10062 CHECK_EQ(3, value->Int32Value());
10064 value = CompileRun(
10065 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
10066 CHECK(value->IsNumber());
10067 CHECK_EQ(3, value->Int32Value());
10069 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
10070 CHECK(value->IsTrue());
10072 // Enumeration doesn't enumerate accessors from inaccessible objects in
10073 // the prototype chain even if the accessors are in themselves accessible.
10074 value = CompileRun(
10076 " var obj = { '__proto__': other };"
10078 " for (var p in obj) {"
10079 " if (p == 'accessible_prop' ||"
10080 " p == 'blocked_js_prop' ||"
10081 " p == 'blocked_js_prop') {"
10090 CHECK(value->IsTrue());
10097 TEST(AccessControlES5) {
10098 v8::Isolate* isolate = CcTest::isolate();
10099 v8::HandleScope handle_scope(isolate);
10100 v8::Handle<v8::ObjectTemplate> global_template =
10101 v8::ObjectTemplate::New(isolate);
10103 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
10104 IndexedAccessBlocker);
10106 // Add accessible accessor.
10107 global_template->SetAccessor(
10108 v8_str("accessible_prop"),
10109 EchoGetter, EchoSetter,
10110 v8::Handle<Value>(),
10111 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
10114 // Add an accessor that is not accessible by cross-domain JS code.
10115 global_template->SetAccessor(v8_str("blocked_prop"),
10116 UnreachableGetter, UnreachableSetter,
10117 v8::Handle<Value>(),
10120 // Create an environment
10121 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
10124 v8::Handle<v8::Object> global0 = context0->Global();
10126 v8::Local<Context> context1 = Context::New(isolate);
10128 v8::Handle<v8::Object> global1 = context1->Global();
10129 global1->Set(v8_str("other"), global0);
10131 // Regression test for issue 1154.
10132 CHECK(CompileRun("Object.keys(other)").IsEmpty());
10133 CHECK(CompileRun("other.blocked_prop").IsEmpty());
10135 // Regression test for issue 1027.
10136 CompileRun("Object.defineProperty(\n"
10137 " other, 'blocked_prop', {configurable: false})");
10138 CHECK(CompileRun("other.blocked_prop").IsEmpty());
10139 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
10142 // Regression test for issue 1171.
10143 ExpectTrue("Object.isExtensible(other)");
10144 CompileRun("Object.preventExtensions(other)");
10145 ExpectTrue("Object.isExtensible(other)");
10147 // Object.seal and Object.freeze.
10148 CompileRun("Object.freeze(other)");
10149 ExpectTrue("Object.isExtensible(other)");
10151 CompileRun("Object.seal(other)");
10152 ExpectTrue("Object.isExtensible(other)");
10154 // Regression test for issue 1250.
10155 // Make sure that we can set the accessible accessors value using normal
10157 CompileRun("other.accessible_prop = 42");
10158 CHECK_EQ(42, g_echo_value);
10160 v8::Handle<Value> value;
10161 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
10162 value = CompileRun("other.accessible_prop == 42");
10163 CHECK(value->IsTrue());
10167 static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
10168 v8::AccessType type, Local<Value> data) {
10173 static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
10174 v8::AccessType type, Local<Value> data) {
10179 THREADED_TEST(AccessControlGetOwnPropertyNames) {
10180 v8::Isolate* isolate = CcTest::isolate();
10181 v8::HandleScope handle_scope(isolate);
10182 v8::Handle<v8::ObjectTemplate> obj_template =
10183 v8::ObjectTemplate::New(isolate);
10185 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10186 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
10187 BlockEverythingIndexed);
10189 // Create an environment
10190 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
10193 v8::Handle<v8::Object> global0 = context0->Global();
10195 v8::HandleScope scope1(CcTest::isolate());
10197 v8::Local<Context> context1 = Context::New(isolate);
10200 v8::Handle<v8::Object> global1 = context1->Global();
10201 global1->Set(v8_str("other"), global0);
10202 global1->Set(v8_str("object"), obj_template->NewInstance());
10204 v8::Handle<Value> value;
10206 // Attempt to get the property names of the other global object and
10207 // of an object that requires access checks. Accessing the other
10208 // global object should be blocked by access checks on the global
10209 // proxy object. Accessing the object that requires access checks
10210 // is blocked by the access checks on the object itself.
10211 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
10212 CHECK(value.IsEmpty());
10214 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
10215 CHECK(value.IsEmpty());
10222 TEST(SuperAccessControl) {
10223 i::FLAG_harmony_classes = true;
10224 v8::Isolate* isolate = CcTest::isolate();
10225 v8::HandleScope handle_scope(isolate);
10226 v8::Handle<v8::ObjectTemplate> obj_template =
10227 v8::ObjectTemplate::New(isolate);
10228 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
10229 BlockEverythingIndexed);
10231 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
10234 v8::TryCatch try_catch;
10236 "function f() { return super.hasOwnProperty; };"
10237 "var m = f.toMethod(prohibited);"
10239 CHECK(try_catch.HasCaught());
10243 v8::TryCatch try_catch;
10245 "function f() { return super[42]; };"
10246 "var m = f.toMethod(prohibited);"
10248 CHECK(try_catch.HasCaught());
10252 v8::TryCatch try_catch;
10254 "function f() { super.hasOwnProperty = function () {}; };"
10255 "var m = f.toMethod(prohibited);"
10257 CHECK(try_catch.HasCaught());
10261 v8::TryCatch try_catch;
10263 "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
10266 " super.x = function () {}; "
10268 "var m = f.toMethod(prohibited);"
10270 CHECK(try_catch.HasCaught());
10275 static void IndexedPropertyEnumerator(
10276 const v8::PropertyCallbackInfo<v8::Array>& info) {
10277 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
10278 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
10279 info.GetReturnValue().Set(result);
10283 static void NamedPropertyEnumerator(
10284 const v8::PropertyCallbackInfo<v8::Array>& info) {
10285 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
10286 result->Set(0, v8_str("x"));
10287 result->Set(1, v8::Symbol::GetIterator(info.GetIsolate()));
10288 info.GetReturnValue().Set(result);
10292 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
10293 v8::Isolate* isolate = CcTest::isolate();
10294 v8::HandleScope handle_scope(isolate);
10295 v8::Handle<v8::ObjectTemplate> obj_template =
10296 v8::ObjectTemplate::New(isolate);
10298 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
10299 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
10300 obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
10301 NULL, NULL, NULL, NULL, IndexedPropertyEnumerator));
10302 obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
10303 NULL, NULL, NULL, NULL, NamedPropertyEnumerator));
10305 LocalContext context;
10306 v8::Handle<v8::Object> global = context->Global();
10307 global->Set(v8_str("object"), obj_template->NewInstance());
10309 v8::Handle<v8::Value> result =
10310 CompileRun("Object.getOwnPropertyNames(object)");
10311 CHECK(result->IsArray());
10312 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
10313 CHECK_EQ(2, result_array->Length());
10314 CHECK(result_array->Get(0)->IsString());
10315 CHECK(result_array->Get(1)->IsString());
10316 CHECK_EQ(v8_str("7"), result_array->Get(0));
10317 CHECK_EQ(v8_str("x"), result_array->Get(1));
10319 result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
10320 CHECK(result->IsArray());
10321 result_array = v8::Handle<v8::Array>::Cast(result);
10322 CHECK_EQ(2, result_array->Length());
10323 CHECK(result_array->Get(0)->IsString());
10324 CHECK(result_array->Get(1)->IsString());
10325 CHECK_EQ(v8_str("7"), result_array->Get(0));
10326 CHECK_EQ(v8_str("x"), result_array->Get(1));
10328 result = CompileRun("Object.getOwnPropertySymbols(object)");
10329 CHECK(result->IsArray());
10330 result_array = v8::Handle<v8::Array>::Cast(result);
10331 CHECK_EQ(1, result_array->Length());
10332 CHECK_EQ(result_array->Get(0), v8::Symbol::GetIterator(isolate));
10336 static void ConstTenGetter(Local<String> name,
10337 const v8::PropertyCallbackInfo<v8::Value>& info) {
10338 info.GetReturnValue().Set(v8_num(10));
10342 THREADED_TEST(CrossDomainAccessors) {
10343 v8::Isolate* isolate = CcTest::isolate();
10344 v8::HandleScope handle_scope(isolate);
10346 v8::Handle<v8::FunctionTemplate> func_template =
10347 v8::FunctionTemplate::New(isolate);
10349 v8::Handle<v8::ObjectTemplate> global_template =
10350 func_template->InstanceTemplate();
10352 v8::Handle<v8::ObjectTemplate> proto_template =
10353 func_template->PrototypeTemplate();
10355 // Add an accessor to proto that's accessible by cross-domain JS code.
10356 proto_template->SetAccessor(v8_str("accessible"),
10358 v8::Handle<Value>(),
10361 // Add an accessor that is not accessible by cross-domain JS code.
10362 global_template->SetAccessor(v8_str("unreachable"),
10363 UnreachableGetter, 0,
10364 v8::Handle<Value>(),
10367 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
10370 Local<v8::Object> global = context0->Global();
10371 // Add a normal property that shadows 'accessible'
10372 global->Set(v8_str("accessible"), v8_num(11));
10374 // Enter a new context.
10375 v8::HandleScope scope1(CcTest::isolate());
10376 v8::Local<Context> context1 = Context::New(isolate);
10379 v8::Handle<v8::Object> global1 = context1->Global();
10380 global1->Set(v8_str("other"), global);
10382 // Should return 10, instead of 11
10383 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
10384 CHECK(value->IsNumber());
10385 CHECK_EQ(10, value->Int32Value());
10387 value = v8_compile("other.unreachable")->Run();
10388 CHECK(value.IsEmpty());
10395 static int named_access_count = 0;
10396 static int indexed_access_count = 0;
10398 static bool NamedAccessCounter(Local<v8::Object> global,
10400 v8::AccessType type,
10401 Local<Value> data) {
10402 named_access_count++;
10407 static bool IndexedAccessCounter(Local<v8::Object> global,
10409 v8::AccessType type,
10410 Local<Value> data) {
10411 indexed_access_count++;
10416 // This one is too easily disturbed by other tests.
10417 TEST(AccessControlIC) {
10418 named_access_count = 0;
10419 indexed_access_count = 0;
10421 v8::Isolate* isolate = CcTest::isolate();
10422 v8::HandleScope handle_scope(isolate);
10424 // Create an environment.
10425 v8::Local<Context> context0 = Context::New(isolate);
10428 // Create an object that requires access-check functions to be
10429 // called for cross-domain access.
10430 v8::Handle<v8::ObjectTemplate> object_template =
10431 v8::ObjectTemplate::New(isolate);
10432 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10433 IndexedAccessCounter);
10434 Local<v8::Object> object = object_template->NewInstance();
10436 v8::HandleScope scope1(isolate);
10438 // Create another environment.
10439 v8::Local<Context> context1 = Context::New(isolate);
10442 // Make easy access to the object from the other environment.
10443 v8::Handle<v8::Object> global1 = context1->Global();
10444 global1->Set(v8_str("obj"), object);
10446 v8::Handle<Value> value;
10448 // Check that the named access-control function is called every time.
10449 CompileRun("function testProp(obj) {"
10450 " for (var i = 0; i < 10; i++) obj.prop = 1;"
10451 " for (var j = 0; j < 10; j++) obj.prop;"
10454 value = CompileRun("testProp(obj)");
10455 CHECK(value->IsNumber());
10456 CHECK_EQ(1, value->Int32Value());
10457 CHECK_EQ(21, named_access_count);
10459 // Check that the named access-control function is called every time.
10460 CompileRun("var p = 'prop';"
10461 "function testKeyed(obj) {"
10462 " for (var i = 0; i < 10; i++) obj[p] = 1;"
10463 " for (var j = 0; j < 10; j++) obj[p];"
10466 // Use obj which requires access checks. No inline caching is used
10468 value = CompileRun("testKeyed(obj)");
10469 CHECK(value->IsNumber());
10470 CHECK_EQ(1, value->Int32Value());
10471 CHECK_EQ(42, named_access_count);
10472 // Force the inline caches into generic state and try again.
10473 CompileRun("testKeyed({ a: 0 })");
10474 CompileRun("testKeyed({ b: 0 })");
10475 value = CompileRun("testKeyed(obj)");
10476 CHECK(value->IsNumber());
10477 CHECK_EQ(1, value->Int32Value());
10478 CHECK_EQ(63, named_access_count);
10480 // Check that the indexed access-control function is called every time.
10481 CompileRun("function testIndexed(obj) {"
10482 " for (var i = 0; i < 10; i++) obj[0] = 1;"
10483 " for (var j = 0; j < 10; j++) obj[0];"
10486 value = CompileRun("testIndexed(obj)");
10487 CHECK(value->IsNumber());
10488 CHECK_EQ(1, value->Int32Value());
10489 CHECK_EQ(21, indexed_access_count);
10490 // Force the inline caches into generic state.
10491 CompileRun("testIndexed(new Array(1))");
10492 // Test that the indexed access check is called.
10493 value = CompileRun("testIndexed(obj)");
10494 CHECK(value->IsNumber());
10495 CHECK_EQ(1, value->Int32Value());
10496 CHECK_EQ(42, indexed_access_count);
10498 // Check that the named access check is called when invoking
10499 // functions on an object that requires access checks.
10500 CompileRun("obj.f = function() {}");
10501 CompileRun("function testCallNormal(obj) {"
10502 " for (var i = 0; i < 10; i++) obj.f();"
10504 CompileRun("testCallNormal(obj)");
10505 CHECK_EQ(74, named_access_count);
10507 // Force obj into slow case.
10508 value = CompileRun("delete obj.prop");
10509 CHECK(value->BooleanValue());
10510 // Force inline caches into dictionary probing mode.
10511 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10512 // Test that the named access check is called.
10513 value = CompileRun("testProp(obj);");
10514 CHECK(value->IsNumber());
10515 CHECK_EQ(1, value->Int32Value());
10516 CHECK_EQ(96, named_access_count);
10518 // Force the call inline cache into dictionary probing mode.
10519 CompileRun("o.f = function() {}; testCallNormal(o)");
10520 // Test that the named access check is still called for each
10521 // invocation of the function.
10522 value = CompileRun("testCallNormal(obj)");
10523 CHECK_EQ(106, named_access_count);
10530 static bool NamedAccessFlatten(Local<v8::Object> global,
10532 v8::AccessType type,
10533 Local<Value> data) {
10537 CHECK(name->IsString());
10539 memset(buf, 0x1, sizeof(buf));
10540 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
10543 uint16_t buf2[100];
10545 memset(buf, 0x1, sizeof(buf));
10546 len = name.As<String>()->Write(buf2);
10553 static bool IndexedAccessFlatten(Local<v8::Object> global,
10555 v8::AccessType type,
10556 Local<Value> data) {
10561 // Regression test. In access checks, operations that may cause
10562 // garbage collection are not allowed. It used to be the case that
10563 // using the Write operation on a string could cause a garbage
10564 // collection due to flattening of the string. This is no longer the
10566 THREADED_TEST(AccessControlFlatten) {
10567 named_access_count = 0;
10568 indexed_access_count = 0;
10570 v8::Isolate* isolate = CcTest::isolate();
10571 v8::HandleScope handle_scope(isolate);
10573 // Create an environment.
10574 v8::Local<Context> context0 = Context::New(isolate);
10577 // Create an object that requires access-check functions to be
10578 // called for cross-domain access.
10579 v8::Handle<v8::ObjectTemplate> object_template =
10580 v8::ObjectTemplate::New(isolate);
10581 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
10582 IndexedAccessFlatten);
10583 Local<v8::Object> object = object_template->NewInstance();
10585 v8::HandleScope scope1(isolate);
10587 // Create another environment.
10588 v8::Local<Context> context1 = Context::New(isolate);
10591 // Make easy access to the object from the other environment.
10592 v8::Handle<v8::Object> global1 = context1->Global();
10593 global1->Set(v8_str("obj"), object);
10595 v8::Handle<Value> value;
10597 value = v8_compile("var p = 'as' + 'df';")->Run();
10598 value = v8_compile("obj[p];")->Run();
10605 static void AccessControlNamedGetter(
10606 Local<Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
10607 info.GetReturnValue().Set(42);
10611 static void AccessControlNamedSetter(
10612 Local<Name>, Local<Value> value,
10613 const v8::PropertyCallbackInfo<v8::Value>& info) {
10614 info.GetReturnValue().Set(value);
10618 static void AccessControlIndexedGetter(
10620 const v8::PropertyCallbackInfo<v8::Value>& info) {
10621 info.GetReturnValue().Set(v8_num(42));
10625 static void AccessControlIndexedSetter(
10627 Local<Value> value,
10628 const v8::PropertyCallbackInfo<v8::Value>& info) {
10629 info.GetReturnValue().Set(value);
10633 THREADED_TEST(AccessControlInterceptorIC) {
10634 named_access_count = 0;
10635 indexed_access_count = 0;
10637 v8::Isolate* isolate = CcTest::isolate();
10638 v8::HandleScope handle_scope(isolate);
10640 // Create an environment.
10641 v8::Local<Context> context0 = Context::New(isolate);
10644 // Create an object that requires access-check functions to be
10645 // called for cross-domain access. The object also has interceptors
10647 v8::Handle<v8::ObjectTemplate> object_template =
10648 v8::ObjectTemplate::New(isolate);
10649 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10650 IndexedAccessCounter);
10651 object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
10652 AccessControlNamedGetter, AccessControlNamedSetter));
10653 object_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
10654 AccessControlIndexedGetter, AccessControlIndexedSetter));
10655 Local<v8::Object> object = object_template->NewInstance();
10657 v8::HandleScope scope1(isolate);
10659 // Create another environment.
10660 v8::Local<Context> context1 = Context::New(isolate);
10663 // Make easy access to the object from the other environment.
10664 v8::Handle<v8::Object> global1 = context1->Global();
10665 global1->Set(v8_str("obj"), object);
10667 v8::Handle<Value> value;
10669 // Check that the named access-control function is called every time
10670 // eventhough there is an interceptor on the object.
10671 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
10672 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
10674 CHECK(value->IsNumber());
10675 CHECK_EQ(42, value->Int32Value());
10676 CHECK_EQ(21, named_access_count);
10678 value = v8_compile("var p = 'x';")->Run();
10679 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
10680 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
10682 CHECK(value->IsNumber());
10683 CHECK_EQ(42, value->Int32Value());
10684 CHECK_EQ(42, named_access_count);
10686 // Check that the indexed access-control function is called every
10687 // time eventhough there is an interceptor on the object.
10688 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
10689 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
10691 CHECK(value->IsNumber());
10692 CHECK_EQ(42, value->Int32Value());
10693 CHECK_EQ(21, indexed_access_count);
10700 THREADED_TEST(Version) {
10701 v8::V8::GetVersion();
10705 static void InstanceFunctionCallback(
10706 const v8::FunctionCallbackInfo<v8::Value>& args) {
10707 ApiTestFuzzer::Fuzz();
10708 args.GetReturnValue().Set(v8_num(12));
10712 THREADED_TEST(InstanceProperties) {
10713 LocalContext context;
10714 v8::Isolate* isolate = context->GetIsolate();
10715 v8::HandleScope handle_scope(isolate);
10717 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10718 Local<ObjectTemplate> instance = t->InstanceTemplate();
10720 instance->Set(v8_str("x"), v8_num(42));
10721 instance->Set(v8_str("f"),
10722 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10724 Local<Value> o = t->GetFunction()->NewInstance();
10726 context->Global()->Set(v8_str("i"), o);
10727 Local<Value> value = CompileRun("i.x");
10728 CHECK_EQ(42, value->Int32Value());
10730 value = CompileRun("i.f()");
10731 CHECK_EQ(12, value->Int32Value());
10735 static void GlobalObjectInstancePropertiesGet(
10736 Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
10737 ApiTestFuzzer::Fuzz();
10741 THREADED_TEST(GlobalObjectInstanceProperties) {
10742 v8::Isolate* isolate = CcTest::isolate();
10743 v8::HandleScope handle_scope(isolate);
10745 Local<Value> global_object;
10747 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10748 t->InstanceTemplate()->SetHandler(
10749 v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
10750 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10751 instance_template->Set(v8_str("x"), v8_num(42));
10752 instance_template->Set(v8_str("f"),
10753 v8::FunctionTemplate::New(isolate,
10754 InstanceFunctionCallback));
10756 // The script to check how Crankshaft compiles missing global function
10757 // invocations. function g is not defined and should throw on call.
10758 const char* script =
10759 "function wrapper(call) {"
10760 " var x = 0, y = 1;"
10761 " for (var i = 0; i < 1000; i++) {"
10767 "for (var i = 0; i < 17; i++) wrapper(false);"
10769 "try { wrapper(true); } catch (e) { thrown = 1; };"
10773 LocalContext env(NULL, instance_template);
10774 // Hold on to the global object so it can be used again in another
10775 // environment initialization.
10776 global_object = env->Global();
10778 Local<Value> value = CompileRun("x");
10779 CHECK_EQ(42, value->Int32Value());
10780 value = CompileRun("f()");
10781 CHECK_EQ(12, value->Int32Value());
10782 value = CompileRun(script);
10783 CHECK_EQ(1, value->Int32Value());
10787 // Create new environment reusing the global object.
10788 LocalContext env(NULL, instance_template, global_object);
10789 Local<Value> value = CompileRun("x");
10790 CHECK_EQ(42, value->Int32Value());
10791 value = CompileRun("f()");
10792 CHECK_EQ(12, value->Int32Value());
10793 value = CompileRun(script);
10794 CHECK_EQ(1, value->Int32Value());
10799 THREADED_TEST(CallKnownGlobalReceiver) {
10800 v8::Isolate* isolate = CcTest::isolate();
10801 v8::HandleScope handle_scope(isolate);
10803 Local<Value> global_object;
10805 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10806 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10808 // The script to check that we leave global object not
10809 // global object proxy on stack when we deoptimize from inside
10810 // arguments evaluation.
10811 // To provoke error we need to both force deoptimization
10812 // from arguments evaluation and to force CallIC to take
10813 // CallIC_Miss code path that can't cope with global proxy.
10814 const char* script =
10815 "function bar(x, y) { try { } finally { } }"
10816 "function baz(x) { try { } finally { } }"
10817 "function bom(x) { try { } finally { } }"
10818 "function foo(x) { bar([x], bom(2)); }"
10819 "for (var i = 0; i < 10000; i++) foo(1);"
10824 LocalContext env(NULL, instance_template);
10825 // Hold on to the global object so it can be used again in another
10826 // environment initialization.
10827 global_object = env->Global();
10828 foo = CompileRun(script);
10832 // Create new environment reusing the global object.
10833 LocalContext env(NULL, instance_template, global_object);
10834 env->Global()->Set(v8_str("foo"), foo);
10835 CompileRun("foo()");
10840 static void ShadowFunctionCallback(
10841 const v8::FunctionCallbackInfo<v8::Value>& args) {
10842 ApiTestFuzzer::Fuzz();
10843 args.GetReturnValue().Set(v8_num(42));
10847 static int shadow_y;
10848 static int shadow_y_setter_call_count;
10849 static int shadow_y_getter_call_count;
10852 static void ShadowYSetter(Local<String>,
10854 const v8::PropertyCallbackInfo<void>&) {
10855 shadow_y_setter_call_count++;
10860 static void ShadowYGetter(Local<String> name,
10861 const v8::PropertyCallbackInfo<v8::Value>& info) {
10862 ApiTestFuzzer::Fuzz();
10863 shadow_y_getter_call_count++;
10864 info.GetReturnValue().Set(v8_num(shadow_y));
10868 static void ShadowIndexedGet(uint32_t index,
10869 const v8::PropertyCallbackInfo<v8::Value>&) {
10873 static void ShadowNamedGet(Local<Name> key,
10874 const v8::PropertyCallbackInfo<v8::Value>&) {}
10877 THREADED_TEST(ShadowObject) {
10878 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10879 v8::Isolate* isolate = CcTest::isolate();
10880 v8::HandleScope handle_scope(isolate);
10882 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10883 LocalContext context(NULL, global_template);
10885 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10886 t->InstanceTemplate()->SetHandler(
10887 v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
10888 t->InstanceTemplate()->SetHandler(
10889 v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
10890 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10891 Local<ObjectTemplate> instance = t->InstanceTemplate();
10893 proto->Set(v8_str("f"),
10894 v8::FunctionTemplate::New(isolate,
10895 ShadowFunctionCallback,
10897 proto->Set(v8_str("x"), v8_num(12));
10899 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10901 Local<Value> o = t->GetFunction()->NewInstance();
10902 context->Global()->Set(v8_str("__proto__"), o);
10904 Local<Value> value =
10905 CompileRun("this.propertyIsEnumerable(0)");
10906 CHECK(value->IsBoolean());
10907 CHECK(!value->BooleanValue());
10909 value = CompileRun("x");
10910 CHECK_EQ(12, value->Int32Value());
10912 value = CompileRun("f()");
10913 CHECK_EQ(42, value->Int32Value());
10915 CompileRun("y = 43");
10916 CHECK_EQ(1, shadow_y_setter_call_count);
10917 value = CompileRun("y");
10918 CHECK_EQ(1, shadow_y_getter_call_count);
10919 CHECK_EQ(42, value->Int32Value());
10923 THREADED_TEST(HiddenPrototype) {
10924 LocalContext context;
10925 v8::Isolate* isolate = context->GetIsolate();
10926 v8::HandleScope handle_scope(isolate);
10928 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10929 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10930 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10931 t1->SetHiddenPrototype(true);
10932 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10933 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10934 t2->SetHiddenPrototype(true);
10935 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10936 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10937 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10939 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10940 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10941 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10942 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10944 // Setting the prototype on an object skips hidden prototypes.
10945 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10946 o0->Set(v8_str("__proto__"), o1);
10947 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10948 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10949 o0->Set(v8_str("__proto__"), o2);
10950 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10951 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10952 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10953 o0->Set(v8_str("__proto__"), o3);
10954 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10955 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10956 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10957 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10959 // Getting the prototype of o0 should get the first visible one
10960 // which is o3. Therefore, z should not be defined on the prototype
10962 Local<Value> proto = o0->Get(v8_str("__proto__"));
10963 CHECK(proto->IsObject());
10964 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10968 THREADED_TEST(HiddenPrototypeSet) {
10969 LocalContext context;
10970 v8::Isolate* isolate = context->GetIsolate();
10971 v8::HandleScope handle_scope(isolate);
10973 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10974 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10975 ht->SetHiddenPrototype(true);
10976 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10977 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10979 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10980 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10981 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10982 o->Set(v8_str("__proto__"), h);
10983 h->Set(v8_str("__proto__"), p);
10985 // Setting a property that exists on the hidden prototype goes there.
10986 o->Set(v8_str("x"), v8_num(7));
10987 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10988 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10989 CHECK(p->Get(v8_str("x"))->IsUndefined());
10991 // Setting a new property should not be forwarded to the hidden prototype.
10992 o->Set(v8_str("y"), v8_num(6));
10993 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10994 CHECK(h->Get(v8_str("y"))->IsUndefined());
10995 CHECK(p->Get(v8_str("y"))->IsUndefined());
10997 // Setting a property that only exists on a prototype of the hidden prototype
10998 // is treated normally again.
10999 p->Set(v8_str("z"), v8_num(8));
11000 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
11001 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
11002 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
11003 o->Set(v8_str("z"), v8_num(9));
11004 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
11005 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
11006 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
11010 // Regression test for issue 2457.
11011 THREADED_TEST(HiddenPrototypeIdentityHash) {
11012 LocalContext context;
11013 v8::HandleScope handle_scope(context->GetIsolate());
11015 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
11016 t->SetHiddenPrototype(true);
11017 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
11018 Handle<Object> p = t->GetFunction()->NewInstance();
11019 Handle<Object> o = Object::New(context->GetIsolate());
11020 o->SetPrototype(p);
11022 int hash = o->GetIdentityHash();
11024 o->Set(v8_str("foo"), v8_num(42));
11025 DCHECK_EQ(hash, o->GetIdentityHash());
11029 THREADED_TEST(SetPrototype) {
11030 LocalContext context;
11031 v8::Isolate* isolate = context->GetIsolate();
11032 v8::HandleScope handle_scope(isolate);
11034 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
11035 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
11036 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11037 t1->SetHiddenPrototype(true);
11038 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
11039 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11040 t2->SetHiddenPrototype(true);
11041 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
11042 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11043 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
11045 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
11046 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
11047 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
11048 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
11050 // Setting the prototype on an object does not skip hidden prototypes.
11051 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11052 CHECK(o0->SetPrototype(o1));
11053 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11054 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
11055 CHECK(o1->SetPrototype(o2));
11056 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11057 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
11058 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
11059 CHECK(o2->SetPrototype(o3));
11060 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
11061 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
11062 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
11063 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
11065 // Getting the prototype of o0 should get the first visible one
11066 // which is o3. Therefore, z should not be defined on the prototype
11068 Local<Value> proto = o0->Get(v8_str("__proto__"));
11069 CHECK(proto->IsObject());
11070 CHECK_EQ(proto.As<v8::Object>(), o3);
11072 // However, Object::GetPrototype ignores hidden prototype.
11073 Local<Value> proto0 = o0->GetPrototype();
11074 CHECK(proto0->IsObject());
11075 CHECK_EQ(proto0.As<v8::Object>(), o1);
11077 Local<Value> proto1 = o1->GetPrototype();
11078 CHECK(proto1->IsObject());
11079 CHECK_EQ(proto1.As<v8::Object>(), o2);
11081 Local<Value> proto2 = o2->GetPrototype();
11082 CHECK(proto2->IsObject());
11083 CHECK_EQ(proto2.As<v8::Object>(), o3);
11087 // Getting property names of an object with a prototype chain that
11088 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
11089 // crash the runtime.
11090 THREADED_TEST(Regress91517) {
11091 i::FLAG_allow_natives_syntax = true;
11092 LocalContext context;
11093 v8::Isolate* isolate = context->GetIsolate();
11094 v8::HandleScope handle_scope(isolate);
11096 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11097 t1->SetHiddenPrototype(true);
11098 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
11099 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11100 t2->SetHiddenPrototype(true);
11101 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
11102 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
11103 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
11104 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
11105 t3->SetHiddenPrototype(true);
11106 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
11107 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
11108 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
11110 // Force dictionary-based properties.
11111 i::ScopedVector<char> name_buf(1024);
11112 for (int i = 1; i <= 1000; i++) {
11113 i::SNPrintF(name_buf, "sdf%d", i);
11114 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
11117 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
11118 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
11119 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
11120 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
11122 // Create prototype chain of hidden prototypes.
11123 CHECK(o4->SetPrototype(o3));
11124 CHECK(o3->SetPrototype(o2));
11125 CHECK(o2->SetPrototype(o1));
11127 // Call the runtime version of GetOwnPropertyNames() on the natively
11128 // created object through JavaScript.
11129 context->Global()->Set(v8_str("obj"), o4);
11130 // PROPERTY_ATTRIBUTES_NONE = 0
11131 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
11133 ExpectInt32("names.length", 1006);
11134 ExpectTrue("names.indexOf(\"baz\") >= 0");
11135 ExpectTrue("names.indexOf(\"boo\") >= 0");
11136 ExpectTrue("names.indexOf(\"foo\") >= 0");
11137 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
11138 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
11139 ExpectFalse("names[1005] == undefined");
11143 // Getting property names of an object with a hidden and inherited
11144 // prototype should not duplicate the accessor properties inherited.
11145 THREADED_TEST(Regress269562) {
11146 i::FLAG_allow_natives_syntax = true;
11147 LocalContext context;
11148 v8::HandleScope handle_scope(context->GetIsolate());
11150 Local<v8::FunctionTemplate> t1 =
11151 v8::FunctionTemplate::New(context->GetIsolate());
11152 t1->SetHiddenPrototype(true);
11154 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
11155 i1->SetAccessor(v8_str("foo"),
11156 SimpleAccessorGetter, SimpleAccessorSetter);
11157 i1->SetAccessor(v8_str("bar"),
11158 SimpleAccessorGetter, SimpleAccessorSetter);
11159 i1->SetAccessor(v8_str("baz"),
11160 SimpleAccessorGetter, SimpleAccessorSetter);
11161 i1->Set(v8_str("n1"), v8_num(1));
11162 i1->Set(v8_str("n2"), v8_num(2));
11164 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
11165 Local<v8::FunctionTemplate> t2 =
11166 v8::FunctionTemplate::New(context->GetIsolate());
11167 t2->SetHiddenPrototype(true);
11169 // Inherit from t1 and mark prototype as hidden.
11171 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
11173 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
11174 CHECK(o2->SetPrototype(o1));
11176 v8::Local<v8::Symbol> sym =
11177 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
11178 o1->Set(sym, v8_num(3));
11179 o1->SetHiddenValue(
11180 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
11182 // Call the runtime version of GetOwnPropertyNames() on
11183 // the natively created object through JavaScript.
11184 context->Global()->Set(v8_str("obj"), o2);
11185 context->Global()->Set(v8_str("sym"), sym);
11186 // PROPERTY_ATTRIBUTES_NONE = 0
11187 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
11189 ExpectInt32("names.length", 7);
11190 ExpectTrue("names.indexOf(\"foo\") >= 0");
11191 ExpectTrue("names.indexOf(\"bar\") >= 0");
11192 ExpectTrue("names.indexOf(\"baz\") >= 0");
11193 ExpectTrue("names.indexOf(\"n1\") >= 0");
11194 ExpectTrue("names.indexOf(\"n2\") >= 0");
11195 ExpectTrue("names.indexOf(sym) >= 0");
11196 ExpectTrue("names.indexOf(\"mine\") >= 0");
11200 THREADED_TEST(FunctionReadOnlyPrototype) {
11201 LocalContext context;
11202 v8::Isolate* isolate = context->GetIsolate();
11203 v8::HandleScope handle_scope(isolate);
11205 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11206 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11207 t1->ReadOnlyPrototype();
11208 context->Global()->Set(v8_str("func1"), t1->GetFunction());
11209 // Configured value of ReadOnly flag.
11212 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
11213 " return (descriptor['writable'] == false);"
11214 "})()")->BooleanValue());
11215 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
11217 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
11219 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
11220 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
11221 context->Global()->Set(v8_str("func2"), t2->GetFunction());
11222 // Default value of ReadOnly flag.
11225 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
11226 " return (descriptor['writable'] == true);"
11227 "})()")->BooleanValue());
11228 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
11232 THREADED_TEST(SetPrototypeThrows) {
11233 LocalContext context;
11234 v8::Isolate* isolate = context->GetIsolate();
11235 v8::HandleScope handle_scope(isolate);
11237 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11239 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
11240 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
11242 CHECK(o0->SetPrototype(o1));
11243 // If setting the prototype leads to the cycle, SetPrototype should
11244 // return false and keep VM in sane state.
11245 v8::TryCatch try_catch;
11246 CHECK(!o1->SetPrototype(o0));
11247 CHECK(!try_catch.HasCaught());
11248 DCHECK(!CcTest::i_isolate()->has_pending_exception());
11250 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
11254 THREADED_TEST(FunctionRemovePrototype) {
11255 LocalContext context;
11256 v8::Isolate* isolate = context->GetIsolate();
11257 v8::HandleScope handle_scope(isolate);
11259 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
11260 t1->RemovePrototype();
11261 Local<v8::Function> fun = t1->GetFunction();
11262 context->Global()->Set(v8_str("fun"), fun);
11263 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
11265 v8::TryCatch try_catch;
11266 CompileRun("new fun()");
11267 CHECK(try_catch.HasCaught());
11270 fun->NewInstance();
11271 CHECK(try_catch.HasCaught());
11275 THREADED_TEST(GetterSetterExceptions) {
11276 LocalContext context;
11277 v8::Isolate* isolate = context->GetIsolate();
11278 v8::HandleScope handle_scope(isolate);
11280 "function Foo() { };"
11281 "function Throw() { throw 5; };"
11283 "x.__defineSetter__('set', Throw);"
11284 "x.__defineGetter__('get', Throw);");
11285 Local<v8::Object> x =
11286 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
11287 v8::TryCatch try_catch;
11288 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
11289 x->Get(v8_str("get"));
11290 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
11291 x->Get(v8_str("get"));
11292 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
11293 x->Get(v8_str("get"));
11294 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
11295 x->Get(v8_str("get"));
11299 THREADED_TEST(Constructor) {
11300 LocalContext context;
11301 v8::Isolate* isolate = context->GetIsolate();
11302 v8::HandleScope handle_scope(isolate);
11303 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11304 templ->SetClassName(v8_str("Fun"));
11305 Local<Function> cons = templ->GetFunction();
11306 context->Global()->Set(v8_str("Fun"), cons);
11307 Local<v8::Object> inst = cons->NewInstance();
11308 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
11309 CHECK(obj->IsJSObject());
11310 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
11311 CHECK(value->BooleanValue());
11315 static void ConstructorCallback(
11316 const v8::FunctionCallbackInfo<v8::Value>& args) {
11317 ApiTestFuzzer::Fuzz();
11318 Local<Object> This;
11320 if (args.IsConstructCall()) {
11321 Local<Object> Holder = args.Holder();
11322 This = Object::New(args.GetIsolate());
11323 Local<Value> proto = Holder->GetPrototype();
11324 if (proto->IsObject()) {
11325 This->SetPrototype(proto);
11328 This = args.This();
11331 This->Set(v8_str("a"), args[0]);
11332 args.GetReturnValue().Set(This);
11336 static void FakeConstructorCallback(
11337 const v8::FunctionCallbackInfo<v8::Value>& args) {
11338 ApiTestFuzzer::Fuzz();
11339 args.GetReturnValue().Set(args[0]);
11343 THREADED_TEST(ConstructorForObject) {
11344 LocalContext context;
11345 v8::Isolate* isolate = context->GetIsolate();
11346 v8::HandleScope handle_scope(isolate);
11348 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11349 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
11350 Local<Object> instance = instance_template->NewInstance();
11351 context->Global()->Set(v8_str("obj"), instance);
11352 v8::TryCatch try_catch;
11353 Local<Value> value;
11354 CHECK(!try_catch.HasCaught());
11356 // Call the Object's constructor with a 32-bit signed integer.
11357 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
11358 CHECK(!try_catch.HasCaught());
11359 CHECK(value->IsInt32());
11360 CHECK_EQ(28, value->Int32Value());
11362 Local<Value> args1[] = { v8_num(28) };
11363 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
11364 CHECK(value_obj1->IsObject());
11365 Local<Object> object1 = Local<Object>::Cast(value_obj1);
11366 value = object1->Get(v8_str("a"));
11367 CHECK(value->IsInt32());
11368 CHECK(!try_catch.HasCaught());
11369 CHECK_EQ(28, value->Int32Value());
11371 // Call the Object's constructor with a String.
11372 value = CompileRun(
11373 "(function() { var o = new obj('tipli'); return o.a; })()");
11374 CHECK(!try_catch.HasCaught());
11375 CHECK(value->IsString());
11376 String::Utf8Value string_value1(value->ToString(isolate));
11377 CHECK_EQ("tipli", *string_value1);
11379 Local<Value> args2[] = { v8_str("tipli") };
11380 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
11381 CHECK(value_obj2->IsObject());
11382 Local<Object> object2 = Local<Object>::Cast(value_obj2);
11383 value = object2->Get(v8_str("a"));
11384 CHECK(!try_catch.HasCaught());
11385 CHECK(value->IsString());
11386 String::Utf8Value string_value2(value->ToString(isolate));
11387 CHECK_EQ("tipli", *string_value2);
11389 // Call the Object's constructor with a Boolean.
11390 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
11391 CHECK(!try_catch.HasCaught());
11392 CHECK(value->IsBoolean());
11393 CHECK_EQ(true, value->BooleanValue());
11395 Handle<Value> args3[] = { v8::True(isolate) };
11396 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
11397 CHECK(value_obj3->IsObject());
11398 Local<Object> object3 = Local<Object>::Cast(value_obj3);
11399 value = object3->Get(v8_str("a"));
11400 CHECK(!try_catch.HasCaught());
11401 CHECK(value->IsBoolean());
11402 CHECK_EQ(true, value->BooleanValue());
11404 // Call the Object's constructor with undefined.
11405 Handle<Value> args4[] = { v8::Undefined(isolate) };
11406 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
11407 CHECK(value_obj4->IsObject());
11408 Local<Object> object4 = Local<Object>::Cast(value_obj4);
11409 value = object4->Get(v8_str("a"));
11410 CHECK(!try_catch.HasCaught());
11411 CHECK(value->IsUndefined());
11413 // Call the Object's constructor with null.
11414 Handle<Value> args5[] = { v8::Null(isolate) };
11415 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
11416 CHECK(value_obj5->IsObject());
11417 Local<Object> object5 = Local<Object>::Cast(value_obj5);
11418 value = object5->Get(v8_str("a"));
11419 CHECK(!try_catch.HasCaught());
11420 CHECK(value->IsNull());
11423 // Check exception handling when there is no constructor set for the Object.
11424 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11425 Local<Object> instance = instance_template->NewInstance();
11426 context->Global()->Set(v8_str("obj2"), instance);
11427 v8::TryCatch try_catch;
11428 Local<Value> value;
11429 CHECK(!try_catch.HasCaught());
11431 value = CompileRun("new obj2(28)");
11432 CHECK(try_catch.HasCaught());
11433 String::Utf8Value exception_value1(try_catch.Exception());
11434 CHECK_EQ("TypeError: object is not a function", *exception_value1);
11437 Local<Value> args[] = { v8_num(29) };
11438 value = instance->CallAsConstructor(1, args);
11439 CHECK(try_catch.HasCaught());
11440 String::Utf8Value exception_value2(try_catch.Exception());
11441 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
11445 // Check the case when constructor throws exception.
11446 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11447 instance_template->SetCallAsFunctionHandler(ThrowValue);
11448 Local<Object> instance = instance_template->NewInstance();
11449 context->Global()->Set(v8_str("obj3"), instance);
11450 v8::TryCatch try_catch;
11451 Local<Value> value;
11452 CHECK(!try_catch.HasCaught());
11454 value = CompileRun("new obj3(22)");
11455 CHECK(try_catch.HasCaught());
11456 String::Utf8Value exception_value1(try_catch.Exception());
11457 CHECK_EQ("22", *exception_value1);
11460 Local<Value> args[] = { v8_num(23) };
11461 value = instance->CallAsConstructor(1, args);
11462 CHECK(try_catch.HasCaught());
11463 String::Utf8Value exception_value2(try_catch.Exception());
11464 CHECK_EQ("23", *exception_value2);
11468 // Check whether constructor returns with an object or non-object.
11469 { Local<FunctionTemplate> function_template =
11470 FunctionTemplate::New(isolate, FakeConstructorCallback);
11471 Local<Function> function = function_template->GetFunction();
11472 Local<Object> instance1 = function;
11473 context->Global()->Set(v8_str("obj4"), instance1);
11474 v8::TryCatch try_catch;
11475 Local<Value> value;
11476 CHECK(!try_catch.HasCaught());
11478 CHECK(instance1->IsObject());
11479 CHECK(instance1->IsFunction());
11481 value = CompileRun("new obj4(28)");
11482 CHECK(!try_catch.HasCaught());
11483 CHECK(value->IsObject());
11485 Local<Value> args1[] = { v8_num(28) };
11486 value = instance1->CallAsConstructor(1, args1);
11487 CHECK(!try_catch.HasCaught());
11488 CHECK(value->IsObject());
11490 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11491 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
11492 Local<Object> instance2 = instance_template->NewInstance();
11493 context->Global()->Set(v8_str("obj5"), instance2);
11494 CHECK(!try_catch.HasCaught());
11496 CHECK(instance2->IsObject());
11497 CHECK(!instance2->IsFunction());
11499 value = CompileRun("new obj5(28)");
11500 CHECK(!try_catch.HasCaught());
11501 CHECK(!value->IsObject());
11503 Local<Value> args2[] = { v8_num(28) };
11504 value = instance2->CallAsConstructor(1, args2);
11505 CHECK(!try_catch.HasCaught());
11506 CHECK(!value->IsObject());
11511 THREADED_TEST(FunctionDescriptorException) {
11512 LocalContext context;
11513 v8::Isolate* isolate = context->GetIsolate();
11514 v8::HandleScope handle_scope(isolate);
11515 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11516 templ->SetClassName(v8_str("Fun"));
11517 Local<Function> cons = templ->GetFunction();
11518 context->Global()->Set(v8_str("Fun"), cons);
11519 Local<Value> value = CompileRun(
11520 "function test() {"
11522 " (new Fun()).blah()"
11524 " var str = String(e);"
11525 // " if (str.indexOf('TypeError') == -1) return 1;"
11526 // " if (str.indexOf('[object Fun]') != -1) return 2;"
11527 // " if (str.indexOf('#<Fun>') == -1) return 3;"
11533 CHECK_EQ(0, value->Int32Value());
11537 THREADED_TEST(EvalAliasedDynamic) {
11538 LocalContext current;
11539 v8::HandleScope scope(current->GetIsolate());
11541 // Tests where aliased eval can only be resolved dynamically.
11542 Local<Script> script = v8_compile(
11545 " with (x) { return eval('foo'); }"
11548 "result1 = f(new Object());"
11549 "result2 = f(this);"
11550 "var x = new Object();"
11551 "x.eval = function(x) { return 1; };"
11552 "result3 = f(x);");
11554 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
11555 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
11556 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
11558 v8::TryCatch try_catch;
11559 script = v8_compile(
11562 " with (x) { return eval('bar'); }"
11564 "result4 = f(this)");
11566 CHECK(!try_catch.HasCaught());
11567 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
11573 THREADED_TEST(CrossEval) {
11574 v8::HandleScope scope(CcTest::isolate());
11575 LocalContext other;
11576 LocalContext current;
11578 Local<String> token = v8_str("<security token>");
11579 other->SetSecurityToken(token);
11580 current->SetSecurityToken(token);
11582 // Set up reference from current to other.
11583 current->Global()->Set(v8_str("other"), other->Global());
11585 // Check that new variables are introduced in other context.
11586 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11588 Local<Value> foo = other->Global()->Get(v8_str("foo"));
11589 CHECK_EQ(1234, foo->Int32Value());
11590 CHECK(!current->Global()->Has(v8_str("foo")));
11592 // Check that writing to non-existing properties introduces them in
11593 // the other context.
11594 script = v8_compile("other.eval('na = 1234')");
11596 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
11597 CHECK(!current->Global()->Has(v8_str("na")));
11599 // Check that global variables in current context are not visible in other
11601 v8::TryCatch try_catch;
11602 script = v8_compile("var bar = 42; other.eval('bar');");
11603 Local<Value> result = script->Run();
11604 CHECK(try_catch.HasCaught());
11607 // Check that local variables in current context are not visible in other
11609 script = v8_compile(
11612 " return other.eval('baz');"
11614 result = script->Run();
11615 CHECK(try_catch.HasCaught());
11618 // Check that global variables in the other environment are visible
11619 // when evaluting code.
11620 other->Global()->Set(v8_str("bis"), v8_num(1234));
11621 script = v8_compile("other.eval('bis')");
11622 CHECK_EQ(1234, script->Run()->Int32Value());
11623 CHECK(!try_catch.HasCaught());
11625 // Check that the 'this' pointer points to the global object evaluating
11627 other->Global()->Set(v8_str("t"), other->Global());
11628 script = v8_compile("other.eval('this == t')");
11629 result = script->Run();
11630 CHECK(result->IsTrue());
11631 CHECK(!try_catch.HasCaught());
11633 // Check that variables introduced in with-statement are not visible in
11635 script = v8_compile("with({x:2}){other.eval('x')}");
11636 result = script->Run();
11637 CHECK(try_catch.HasCaught());
11640 // Check that you cannot use 'eval.call' with another object than the
11641 // current global object.
11642 script = v8_compile("other.y = 1; eval.call(other, 'y')");
11643 result = script->Run();
11644 CHECK(try_catch.HasCaught());
11648 // Test that calling eval in a context which has been detached from
11649 // its global proxy works.
11650 THREADED_TEST(EvalInDetachedGlobal) {
11651 v8::Isolate* isolate = CcTest::isolate();
11652 v8::HandleScope scope(isolate);
11654 v8::Local<Context> context0 = Context::New(isolate);
11655 v8::Local<Context> context1 = Context::New(isolate);
11657 // Set up function in context0 that uses eval from context0.
11659 v8::Handle<v8::Value> fun =
11660 CompileRun("var x = 42;"
11663 " return function(s) { return e(s); }"
11667 // Put the function into context1 and call it before and after
11668 // detaching the global. Before detaching, the call succeeds and
11669 // after detaching and exception is thrown.
11671 context1->Global()->Set(v8_str("fun"), fun);
11672 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
11673 CHECK_EQ(42, x_value->Int32Value());
11674 context0->DetachGlobal();
11675 v8::TryCatch catcher;
11676 x_value = CompileRun("fun('x')");
11677 CHECK_EQ(42, x_value->Int32Value());
11682 THREADED_TEST(CrossLazyLoad) {
11683 v8::HandleScope scope(CcTest::isolate());
11684 LocalContext other;
11685 LocalContext current;
11687 Local<String> token = v8_str("<security token>");
11688 other->SetSecurityToken(token);
11689 current->SetSecurityToken(token);
11691 // Set up reference from current to other.
11692 current->Global()->Set(v8_str("other"), other->Global());
11694 // Trigger lazy loading in other context.
11695 Local<Script> script = v8_compile("other.eval('new Date(42)')");
11696 Local<Value> value = script->Run();
11697 CHECK_EQ(42.0, value->NumberValue());
11701 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11702 ApiTestFuzzer::Fuzz();
11703 if (args.IsConstructCall()) {
11704 if (args[0]->IsInt32()) {
11705 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
11710 args.GetReturnValue().Set(args[0]);
11714 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11715 args.GetReturnValue().Set(args.This());
11719 // Test that a call handler can be set for objects which will allow
11720 // non-function objects created through the API to be called as
11722 THREADED_TEST(CallAsFunction) {
11723 LocalContext context;
11724 v8::Isolate* isolate = context->GetIsolate();
11725 v8::HandleScope scope(isolate);
11727 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11728 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11729 instance_template->SetCallAsFunctionHandler(call_as_function);
11730 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11731 context->Global()->Set(v8_str("obj"), instance);
11732 v8::TryCatch try_catch;
11733 Local<Value> value;
11734 CHECK(!try_catch.HasCaught());
11736 value = CompileRun("obj(42)");
11737 CHECK(!try_catch.HasCaught());
11738 CHECK_EQ(42, value->Int32Value());
11740 value = CompileRun("(function(o){return o(49)})(obj)");
11741 CHECK(!try_catch.HasCaught());
11742 CHECK_EQ(49, value->Int32Value());
11744 // test special case of call as function
11745 value = CompileRun("[obj]['0'](45)");
11746 CHECK(!try_catch.HasCaught());
11747 CHECK_EQ(45, value->Int32Value());
11749 value = CompileRun("obj.call = Function.prototype.call;"
11750 "obj.call(null, 87)");
11751 CHECK(!try_catch.HasCaught());
11752 CHECK_EQ(87, value->Int32Value());
11754 // Regression tests for bug #1116356: Calling call through call/apply
11755 // must work for non-function receivers.
11756 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11757 value = CompileRun(apply_99);
11758 CHECK(!try_catch.HasCaught());
11759 CHECK_EQ(99, value->Int32Value());
11761 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11762 value = CompileRun(call_17);
11763 CHECK(!try_catch.HasCaught());
11764 CHECK_EQ(17, value->Int32Value());
11766 // Check that the call-as-function handler can be called through
11768 value = CompileRun("new obj(43)");
11769 CHECK(!try_catch.HasCaught());
11770 CHECK_EQ(-43, value->Int32Value());
11772 // Check that the call-as-function handler can be called through
11774 v8::Handle<Value> args[] = { v8_num(28) };
11775 value = instance->CallAsFunction(instance, 1, args);
11776 CHECK(!try_catch.HasCaught());
11777 CHECK_EQ(28, value->Int32Value());
11780 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11781 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11782 USE(instance_template);
11783 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11784 context->Global()->Set(v8_str("obj2"), instance);
11785 v8::TryCatch try_catch;
11786 Local<Value> value;
11787 CHECK(!try_catch.HasCaught());
11789 // Call an object without call-as-function handler through the JS
11790 value = CompileRun("obj2(28)");
11791 CHECK(value.IsEmpty());
11792 CHECK(try_catch.HasCaught());
11793 String::Utf8Value exception_value1(try_catch.Exception());
11794 // TODO(verwaest): Better message
11795 CHECK_EQ("TypeError: object is not a function",
11796 *exception_value1);
11799 // Call an object without call-as-function handler through the API
11800 value = CompileRun("obj2(28)");
11801 v8::Handle<Value> args[] = { v8_num(28) };
11802 value = instance->CallAsFunction(instance, 1, args);
11803 CHECK(value.IsEmpty());
11804 CHECK(try_catch.HasCaught());
11805 String::Utf8Value exception_value2(try_catch.Exception());
11806 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11810 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11811 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11812 instance_template->SetCallAsFunctionHandler(ThrowValue);
11813 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11814 context->Global()->Set(v8_str("obj3"), instance);
11815 v8::TryCatch try_catch;
11816 Local<Value> value;
11817 CHECK(!try_catch.HasCaught());
11819 // Catch the exception which is thrown by call-as-function handler
11820 value = CompileRun("obj3(22)");
11821 CHECK(try_catch.HasCaught());
11822 String::Utf8Value exception_value1(try_catch.Exception());
11823 CHECK_EQ("22", *exception_value1);
11826 v8::Handle<Value> args[] = { v8_num(23) };
11827 value = instance->CallAsFunction(instance, 1, args);
11828 CHECK(try_catch.HasCaught());
11829 String::Utf8Value exception_value2(try_catch.Exception());
11830 CHECK_EQ("23", *exception_value2);
11834 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11835 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11836 instance_template->SetCallAsFunctionHandler(ReturnThis);
11837 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11839 Local<v8::Value> a1 =
11840 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11841 CHECK(a1->StrictEquals(instance));
11842 Local<v8::Value> a2 =
11843 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11844 CHECK(a2->StrictEquals(instance));
11845 Local<v8::Value> a3 =
11846 instance->CallAsFunction(v8_num(42), 0, NULL);
11847 CHECK(a3->StrictEquals(instance));
11848 Local<v8::Value> a4 =
11849 instance->CallAsFunction(v8_str("hello"), 0, NULL);
11850 CHECK(a4->StrictEquals(instance));
11851 Local<v8::Value> a5 =
11852 instance->CallAsFunction(v8::True(isolate), 0, NULL);
11853 CHECK(a5->StrictEquals(instance));
11857 "function ReturnThisSloppy() {"
11860 "function ReturnThisStrict() {"
11864 Local<Function> ReturnThisSloppy =
11865 Local<Function>::Cast(
11866 context->Global()->Get(v8_str("ReturnThisSloppy")));
11867 Local<Function> ReturnThisStrict =
11868 Local<Function>::Cast(
11869 context->Global()->Get(v8_str("ReturnThisStrict")));
11871 Local<v8::Value> a1 =
11872 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11873 CHECK(a1->StrictEquals(context->Global()));
11874 Local<v8::Value> a2 =
11875 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11876 CHECK(a2->StrictEquals(context->Global()));
11877 Local<v8::Value> a3 =
11878 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11879 CHECK(a3->IsNumberObject());
11880 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11881 Local<v8::Value> a4 =
11882 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11883 CHECK(a4->IsStringObject());
11884 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11885 Local<v8::Value> a5 =
11886 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11887 CHECK(a5->IsBooleanObject());
11888 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11890 Local<v8::Value> a6 =
11891 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11892 CHECK(a6->IsUndefined());
11893 Local<v8::Value> a7 =
11894 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11895 CHECK(a7->IsNull());
11896 Local<v8::Value> a8 =
11897 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11898 CHECK(a8->StrictEquals(v8_num(42)));
11899 Local<v8::Value> a9 =
11900 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11901 CHECK(a9->StrictEquals(v8_str("hello")));
11902 Local<v8::Value> a10 =
11903 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11904 CHECK(a10->StrictEquals(v8::True(isolate)));
11909 // Check whether a non-function object is callable.
11910 THREADED_TEST(CallableObject) {
11911 LocalContext context;
11912 v8::Isolate* isolate = context->GetIsolate();
11913 v8::HandleScope scope(isolate);
11915 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11916 instance_template->SetCallAsFunctionHandler(call_as_function);
11917 Local<Object> instance = instance_template->NewInstance();
11918 v8::TryCatch try_catch;
11920 CHECK(instance->IsCallable());
11921 CHECK(!try_catch.HasCaught());
11924 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11925 Local<Object> instance = instance_template->NewInstance();
11926 v8::TryCatch try_catch;
11928 CHECK(!instance->IsCallable());
11929 CHECK(!try_catch.HasCaught());
11932 { Local<FunctionTemplate> function_template =
11933 FunctionTemplate::New(isolate, call_as_function);
11934 Local<Function> function = function_template->GetFunction();
11935 Local<Object> instance = function;
11936 v8::TryCatch try_catch;
11938 CHECK(instance->IsCallable());
11939 CHECK(!try_catch.HasCaught());
11942 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11943 Local<Function> function = function_template->GetFunction();
11944 Local<Object> instance = function;
11945 v8::TryCatch try_catch;
11947 CHECK(instance->IsCallable());
11948 CHECK(!try_catch.HasCaught());
11953 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11954 v8::HandleScope scope(isolate);
11955 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11956 for (int i = 0; i < iterations; i++) {
11957 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11959 return Recurse(isolate, depth - 1, iterations);
11963 THREADED_TEST(HandleIteration) {
11964 static const int kIterations = 500;
11965 static const int kNesting = 200;
11966 LocalContext context;
11967 v8::Isolate* isolate = context->GetIsolate();
11968 v8::HandleScope scope0(isolate);
11969 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11971 v8::HandleScope scope1(isolate);
11972 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11973 for (int i = 0; i < kIterations; i++) {
11974 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11975 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11978 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11980 v8::HandleScope scope2(CcTest::isolate());
11981 for (int j = 0; j < kIterations; j++) {
11982 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11983 CHECK_EQ(j + 1 + kIterations,
11984 v8::HandleScope::NumberOfHandles(isolate));
11987 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11989 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11990 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11994 static void InterceptorHasOwnPropertyGetter(
11995 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
11996 ApiTestFuzzer::Fuzz();
12000 THREADED_TEST(InterceptorHasOwnProperty) {
12001 LocalContext context;
12002 v8::Isolate* isolate = context->GetIsolate();
12003 v8::HandleScope scope(isolate);
12004 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
12005 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
12006 instance_templ->SetHandler(
12007 v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
12008 Local<Function> function = fun_templ->GetFunction();
12009 context->Global()->Set(v8_str("constructor"), function);
12010 v8::Handle<Value> value = CompileRun(
12011 "var o = new constructor();"
12012 "o.hasOwnProperty('ostehaps');");
12013 CHECK_EQ(false, value->BooleanValue());
12014 value = CompileRun(
12016 "o.hasOwnProperty('ostehaps');");
12017 CHECK_EQ(true, value->BooleanValue());
12018 value = CompileRun(
12019 "var p = new constructor();"
12020 "p.hasOwnProperty('ostehaps');");
12021 CHECK_EQ(false, value->BooleanValue());
12025 static void InterceptorHasOwnPropertyGetterGC(
12026 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12027 ApiTestFuzzer::Fuzz();
12028 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12032 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
12033 LocalContext context;
12034 v8::Isolate* isolate = context->GetIsolate();
12035 v8::HandleScope scope(isolate);
12036 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
12037 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
12038 instance_templ->SetHandler(
12039 v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
12040 Local<Function> function = fun_templ->GetFunction();
12041 context->Global()->Set(v8_str("constructor"), function);
12042 // Let's first make some stuff so we can be sure to get a good GC.
12044 "function makestr(size) {"
12046 " case 1: return 'f';"
12047 " case 2: return 'fo';"
12048 " case 3: return 'foo';"
12050 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
12052 "var x = makestr(12345);"
12053 "x = makestr(31415);"
12054 "x = makestr(23456);");
12055 v8::Handle<Value> value = CompileRun(
12056 "var o = new constructor();"
12057 "o.__proto__ = new String(x);"
12058 "o.hasOwnProperty('ostehaps');");
12059 CHECK_EQ(false, value->BooleanValue());
12063 static void CheckInterceptorLoadIC(
12064 v8::GenericNamedPropertyGetterCallback getter, const char* source,
12066 v8::Isolate* isolate = CcTest::isolate();
12067 v8::HandleScope scope(isolate);
12068 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12069 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(getter, 0, 0, 0, 0,
12071 LocalContext context;
12072 context->Global()->Set(v8_str("o"), templ->NewInstance());
12073 v8::Handle<Value> value = CompileRun(source);
12074 CHECK_EQ(expected, value->Int32Value());
12078 static void InterceptorLoadICGetter(
12079 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12080 ApiTestFuzzer::Fuzz();
12081 v8::Isolate* isolate = CcTest::isolate();
12082 CHECK_EQ(isolate, info.GetIsolate());
12083 CHECK_EQ(v8_str("data"), info.Data());
12084 CHECK_EQ(v8_str("x"), name);
12085 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
12089 // This test should hit the load IC for the interceptor case.
12090 THREADED_TEST(InterceptorLoadIC) {
12091 CheckInterceptorLoadIC(InterceptorLoadICGetter,
12093 "for (var i = 0; i < 1000; i++) {"
12100 // Below go several tests which verify that JITing for various
12101 // configurations of interceptor and explicit fields works fine
12102 // (those cases are special cased to get better performance).
12104 static void InterceptorLoadXICGetter(
12105 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12106 ApiTestFuzzer::Fuzz();
12107 info.GetReturnValue().Set(
12108 v8_str("x")->Equals(name) ?
12109 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
12110 v8::Handle<v8::Value>());
12114 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
12115 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12118 "for (var i = 0; i < 1000; i++) {"
12125 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
12126 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12128 "o.__proto__ = { 'y': 239 };"
12129 "for (var i = 0; i < 1000; i++) {"
12130 " result = o.y + o.x;"
12136 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
12137 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12139 "o.__proto__.y = 239;"
12140 "for (var i = 0; i < 1000; i++) {"
12141 " result = o.y + o.x;"
12147 THREADED_TEST(InterceptorLoadICUndefined) {
12148 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12150 "for (var i = 0; i < 1000; i++) {"
12151 " result = (o.y == undefined) ? 239 : 42;"
12157 THREADED_TEST(InterceptorLoadICWithOverride) {
12158 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12159 "fst = new Object(); fst.__proto__ = o;"
12160 "snd = new Object(); snd.__proto__ = fst;"
12162 "for (var i = 0; i < 1000; i++) {"
12163 " result1 = snd.x;"
12167 "for (var i = 0; i < 1000; i++) {"
12170 "result + result1",
12175 // Test the case when we stored field into
12176 // a stub, but interceptor produced value on its own.
12177 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
12178 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12179 "proto = new Object();"
12180 "o.__proto__ = proto;"
12182 "for (var i = 0; i < 1000; i++) {"
12184 // Now it should be ICed and keep a reference to x defined on proto
12187 "for (var i = 0; i < 1000; i++) {"
12195 // Test the case when we stored field into
12196 // a stub, but it got invalidated later on.
12197 THREADED_TEST(InterceptorLoadICInvalidatedField) {
12198 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12199 "proto1 = new Object();"
12200 "proto2 = new Object();"
12201 "o.__proto__ = proto1;"
12202 "proto1.__proto__ = proto2;"
12204 "for (var i = 0; i < 1000; i++) {"
12206 // Now it should be ICed and keep a reference to y defined on proto2
12210 "for (var i = 0; i < 1000; i++) {"
12218 static int interceptor_load_not_handled_calls = 0;
12219 static void InterceptorLoadNotHandled(
12220 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12221 ++interceptor_load_not_handled_calls;
12225 // Test how post-interceptor lookups are done in the non-cacheable
12226 // case: the interceptor should not be invoked during this lookup.
12227 THREADED_TEST(InterceptorLoadICPostInterceptor) {
12228 interceptor_load_not_handled_calls = 0;
12229 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
12230 "receiver = new Object();"
12231 "receiver.__proto__ = o;"
12232 "proto = new Object();"
12233 "/* Make proto a slow-case object. */"
12234 "for (var i = 0; i < 1000; i++) {"
12235 " proto[\"xxxxxxxx\" + i] = [];"
12238 "o.__proto__ = proto;"
12240 "for (var i = 0; i < 1000; i++) {"
12241 " result += receiver.x;"
12245 CHECK_EQ(1000, interceptor_load_not_handled_calls);
12249 // Test the case when we stored field into
12250 // a stub, but it got invalidated later on due to override on
12251 // global object which is between interceptor and fields' holders.
12252 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
12253 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
12254 "o.__proto__ = this;" // set a global to be a proto of o.
12255 "this.__proto__.y = 239;"
12256 "for (var i = 0; i < 10; i++) {"
12257 " if (o.y != 239) throw 'oops: ' + o.y;"
12258 // Now it should be ICed and keep a reference to y defined on field_holder.
12260 "this.y = 42;" // Assign on a global.
12262 "for (var i = 0; i < 10; i++) {"
12270 static void SetOnThis(Local<String> name,
12271 Local<Value> value,
12272 const v8::PropertyCallbackInfo<void>& info) {
12273 Local<Object>::Cast(info.This())->ForceSet(name, value);
12277 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
12278 v8::Isolate* isolate = CcTest::isolate();
12279 v8::HandleScope scope(isolate);
12280 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12282 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12283 templ->SetAccessor(v8_str("y"), Return239Callback);
12284 LocalContext context;
12285 context->Global()->Set(v8_str("o"), templ->NewInstance());
12287 // Check the case when receiver and interceptor's holder
12288 // are the same objects.
12289 v8::Handle<Value> value = CompileRun(
12291 "for (var i = 0; i < 7; i++) {"
12294 CHECK_EQ(239, value->Int32Value());
12296 // Check the case when interceptor's holder is in proto chain
12298 value = CompileRun(
12299 "r = { __proto__: o };"
12301 "for (var i = 0; i < 7; i++) {"
12304 CHECK_EQ(239, value->Int32Value());
12308 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
12309 v8::Isolate* isolate = CcTest::isolate();
12310 v8::HandleScope scope(isolate);
12311 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12312 templ_o->SetHandler(
12313 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12314 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12315 templ_p->SetAccessor(v8_str("y"), Return239Callback);
12317 LocalContext context;
12318 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12319 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12321 // Check the case when receiver and interceptor's holder
12322 // are the same objects.
12323 v8::Handle<Value> value = CompileRun(
12326 "for (var i = 0; i < 7; i++) {"
12327 " result = o.x + o.y;"
12329 CHECK_EQ(239 + 42, value->Int32Value());
12331 // Check the case when interceptor's holder is in proto chain
12333 value = CompileRun(
12334 "r = { __proto__: o };"
12336 "for (var i = 0; i < 7; i++) {"
12337 " result = r.x + r.y;"
12339 CHECK_EQ(239 + 42, value->Int32Value());
12343 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
12344 v8::Isolate* isolate = CcTest::isolate();
12345 v8::HandleScope scope(isolate);
12346 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12348 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12349 templ->SetAccessor(v8_str("y"), Return239Callback);
12351 LocalContext context;
12352 context->Global()->Set(v8_str("o"), templ->NewInstance());
12354 v8::Handle<Value> value = CompileRun(
12355 "fst = new Object(); fst.__proto__ = o;"
12356 "snd = new Object(); snd.__proto__ = fst;"
12358 "for (var i = 0; i < 7; i++) {"
12359 " result1 = snd.x;"
12363 "for (var i = 0; i < 7; i++) {"
12366 "result + result1");
12367 CHECK_EQ(239 + 42, value->Int32Value());
12371 // Test the case when we stored callback into
12372 // a stub, but interceptor produced value on its own.
12373 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
12374 v8::Isolate* isolate = CcTest::isolate();
12375 v8::HandleScope scope(isolate);
12376 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12377 templ_o->SetHandler(
12378 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12379 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12380 templ_p->SetAccessor(v8_str("y"), Return239Callback);
12382 LocalContext context;
12383 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12384 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12386 v8::Handle<Value> value = CompileRun(
12388 "for (var i = 0; i < 7; i++) {"
12390 // Now it should be ICed and keep a reference to x defined on p
12393 "for (var i = 0; i < 7; i++) {"
12397 CHECK_EQ(42 * 7, value->Int32Value());
12401 // Test the case when we stored callback into
12402 // a stub, but it got invalidated later on.
12403 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
12404 v8::Isolate* isolate = CcTest::isolate();
12405 v8::HandleScope scope(isolate);
12406 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12407 templ_o->SetHandler(
12408 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12409 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12410 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
12412 LocalContext context;
12413 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12414 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12416 v8::Handle<Value> value = CompileRun(
12417 "inbetween = new Object();"
12418 "o.__proto__ = inbetween;"
12419 "inbetween.__proto__ = p;"
12420 "for (var i = 0; i < 10; i++) {"
12422 // Now it should be ICed and keep a reference to y defined on p
12424 "inbetween.y = 42;"
12426 "for (var i = 0; i < 10; i++) {"
12430 CHECK_EQ(42 * 10, value->Int32Value());
12434 // Test the case when we stored callback into
12435 // a stub, but it got invalidated later on due to override on
12436 // global object which is between interceptor and callbacks' holders.
12437 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
12438 v8::Isolate* isolate = CcTest::isolate();
12439 v8::HandleScope scope(isolate);
12440 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12441 templ_o->SetHandler(
12442 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12443 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12444 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
12446 LocalContext context;
12447 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12448 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12450 v8::Handle<Value> value = CompileRun(
12451 "o.__proto__ = this;"
12452 "this.__proto__ = p;"
12453 "for (var i = 0; i < 10; i++) {"
12454 " if (o.y != 239) throw 'oops: ' + o.y;"
12455 // Now it should be ICed and keep a reference to y defined on p
12459 "for (var i = 0; i < 10; i++) {"
12463 CHECK_EQ(42 * 10, value->Int32Value());
12467 static void InterceptorLoadICGetter0(
12468 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12469 ApiTestFuzzer::Fuzz();
12470 CHECK(v8_str("x")->Equals(name));
12471 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
12475 THREADED_TEST(InterceptorReturningZero) {
12476 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
12477 "o.x == undefined ? 1 : 0",
12482 static void InterceptorStoreICSetter(
12483 Local<Name> key, Local<Value> value,
12484 const v8::PropertyCallbackInfo<v8::Value>& info) {
12485 CHECK(v8_str("x")->Equals(key));
12486 CHECK_EQ(42, value->Int32Value());
12487 info.GetReturnValue().Set(value);
12491 // This test should hit the store IC for the interceptor case.
12492 THREADED_TEST(InterceptorStoreIC) {
12493 v8::Isolate* isolate = CcTest::isolate();
12494 v8::HandleScope scope(isolate);
12495 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12496 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
12497 InterceptorLoadICGetter, InterceptorStoreICSetter, 0, 0, 0,
12499 LocalContext context;
12500 context->Global()->Set(v8_str("o"), templ->NewInstance());
12502 "for (var i = 0; i < 1000; i++) {"
12508 THREADED_TEST(InterceptorStoreICWithNoSetter) {
12509 v8::Isolate* isolate = CcTest::isolate();
12510 v8::HandleScope scope(isolate);
12511 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12513 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
12514 LocalContext context;
12515 context->Global()->Set(v8_str("o"), templ->NewInstance());
12516 v8::Handle<Value> value = CompileRun(
12517 "for (var i = 0; i < 1000; i++) {"
12521 CHECK_EQ(239 + 42, value->Int32Value());
12527 v8::Handle<Value> call_ic_function;
12528 v8::Handle<Value> call_ic_function2;
12529 v8::Handle<Value> call_ic_function3;
12531 static void InterceptorCallICGetter(
12532 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12533 ApiTestFuzzer::Fuzz();
12534 CHECK(v8_str("x")->Equals(name));
12535 info.GetReturnValue().Set(call_ic_function);
12539 // This test should hit the call IC for the interceptor case.
12540 THREADED_TEST(InterceptorCallIC) {
12541 v8::Isolate* isolate = CcTest::isolate();
12542 v8::HandleScope scope(isolate);
12543 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12545 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
12546 LocalContext context;
12547 context->Global()->Set(v8_str("o"), templ->NewInstance());
12549 v8_compile("function f(x) { return x + 1; }; f")->Run();
12550 v8::Handle<Value> value = CompileRun(
12552 "for (var i = 0; i < 1000; i++) {"
12553 " result = o.x(41);"
12555 CHECK_EQ(42, value->Int32Value());
12559 // This test checks that if interceptor doesn't provide
12560 // a value, we can fetch regular value.
12561 THREADED_TEST(InterceptorCallICSeesOthers) {
12562 v8::Isolate* isolate = CcTest::isolate();
12563 v8::HandleScope scope(isolate);
12564 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12565 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12566 LocalContext context;
12567 context->Global()->Set(v8_str("o"), templ->NewInstance());
12568 v8::Handle<Value> value = CompileRun(
12569 "o.x = function f(x) { return x + 1; };"
12571 "for (var i = 0; i < 7; i++) {"
12572 " result = o.x(41);"
12574 CHECK_EQ(42, value->Int32Value());
12578 static v8::Handle<Value> call_ic_function4;
12579 static void InterceptorCallICGetter4(
12580 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12581 ApiTestFuzzer::Fuzz();
12582 CHECK(v8_str("x")->Equals(name));
12583 info.GetReturnValue().Set(call_ic_function4);
12587 // This test checks that if interceptor provides a function,
12588 // even if we cached shadowed variant, interceptor's function
12590 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
12591 v8::Isolate* isolate = CcTest::isolate();
12592 v8::HandleScope scope(isolate);
12593 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12595 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
12596 LocalContext context;
12597 context->Global()->Set(v8_str("o"), templ->NewInstance());
12598 call_ic_function4 =
12599 v8_compile("function f(x) { return x - 1; }; f")->Run();
12600 v8::Handle<Value> value = CompileRun(
12601 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
12603 "for (var i = 0; i < 1000; i++) {"
12604 " result = o.x(42);"
12606 CHECK_EQ(41, value->Int32Value());
12610 // Test the case when we stored cacheable lookup into
12611 // a stub, but it got invalidated later on
12612 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
12613 v8::Isolate* isolate = CcTest::isolate();
12614 v8::HandleScope scope(isolate);
12615 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12616 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12617 LocalContext context;
12618 context->Global()->Set(v8_str("o"), templ->NewInstance());
12619 v8::Handle<Value> value = CompileRun(
12620 "proto1 = new Object();"
12621 "proto2 = new Object();"
12622 "o.__proto__ = proto1;"
12623 "proto1.__proto__ = proto2;"
12624 "proto2.y = function(x) { return x + 1; };"
12625 // Invoke it many times to compile a stub
12626 "for (var i = 0; i < 7; i++) {"
12629 "proto1.y = function(x) { return x - 1; };"
12631 "for (var i = 0; i < 7; i++) {"
12632 " result += o.y(42);"
12634 CHECK_EQ(41 * 7, value->Int32Value());
12638 // This test checks that if interceptor doesn't provide a function,
12639 // cached constant function is used
12640 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
12641 v8::Isolate* isolate = CcTest::isolate();
12642 v8::HandleScope scope(isolate);
12643 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12644 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12645 LocalContext context;
12646 context->Global()->Set(v8_str("o"), templ->NewInstance());
12647 v8::Handle<Value> value = CompileRun(
12648 "function inc(x) { return x + 1; };"
12652 "for (var i = 0; i < 1000; i++) {"
12653 " result = o.x(42);"
12655 CHECK_EQ(43, value->Int32Value());
12659 static v8::Handle<Value> call_ic_function5;
12660 static void InterceptorCallICGetter5(
12661 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12662 ApiTestFuzzer::Fuzz();
12663 if (v8_str("x")->Equals(name))
12664 info.GetReturnValue().Set(call_ic_function5);
12668 // This test checks that if interceptor provides a function,
12669 // even if we cached constant function, interceptor's function
12671 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
12672 v8::Isolate* isolate = CcTest::isolate();
12673 v8::HandleScope scope(isolate);
12674 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12676 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
12677 LocalContext context;
12678 context->Global()->Set(v8_str("o"), templ->NewInstance());
12679 call_ic_function5 =
12680 v8_compile("function f(x) { return x - 1; }; f")->Run();
12681 v8::Handle<Value> value = CompileRun(
12682 "function inc(x) { return x + 1; };"
12686 "for (var i = 0; i < 1000; i++) {"
12687 " result = o.x(42);"
12689 CHECK_EQ(41, value->Int32Value());
12693 static v8::Handle<Value> call_ic_function6;
12694 static void InterceptorCallICGetter6(
12695 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12696 ApiTestFuzzer::Fuzz();
12697 if (v8_str("x")->Equals(name))
12698 info.GetReturnValue().Set(call_ic_function6);
12702 // Same test as above, except the code is wrapped in a function
12703 // to test the optimized compiler.
12704 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
12705 i::FLAG_allow_natives_syntax = true;
12706 v8::Isolate* isolate = CcTest::isolate();
12707 v8::HandleScope scope(isolate);
12708 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12710 v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
12711 LocalContext context;
12712 context->Global()->Set(v8_str("o"), templ->NewInstance());
12713 call_ic_function6 =
12714 v8_compile("function f(x) { return x - 1; }; f")->Run();
12715 v8::Handle<Value> value = CompileRun(
12716 "function inc(x) { return x + 1; };"
12719 "function test() {"
12721 " for (var i = 0; i < 1000; i++) {"
12722 " result = o.x(42);"
12729 "%OptimizeFunctionOnNextCall(test);"
12731 CHECK_EQ(41, value->Int32Value());
12735 // Test the case when we stored constant function into
12736 // a stub, but it got invalidated later on
12737 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
12738 v8::Isolate* isolate = CcTest::isolate();
12739 v8::HandleScope scope(isolate);
12740 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12741 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12742 LocalContext context;
12743 context->Global()->Set(v8_str("o"), templ->NewInstance());
12744 v8::Handle<Value> value = CompileRun(
12745 "function inc(x) { return x + 1; };"
12747 "proto1 = new Object();"
12748 "proto2 = new Object();"
12749 "o.__proto__ = proto1;"
12750 "proto1.__proto__ = proto2;"
12752 // Invoke it many times to compile a stub
12753 "for (var i = 0; i < 7; i++) {"
12756 "proto1.y = function(x) { return x - 1; };"
12758 "for (var i = 0; i < 7; i++) {"
12759 " result += o.y(42);"
12761 CHECK_EQ(41 * 7, value->Int32Value());
12765 // Test the case when we stored constant function into
12766 // a stub, but it got invalidated later on due to override on
12767 // global object which is between interceptor and constant function' holders.
12768 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
12769 v8::Isolate* isolate = CcTest::isolate();
12770 v8::HandleScope scope(isolate);
12771 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12772 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12773 LocalContext context;
12774 context->Global()->Set(v8_str("o"), templ->NewInstance());
12775 v8::Handle<Value> value = CompileRun(
12776 "function inc(x) { return x + 1; };"
12778 "o.__proto__ = this;"
12779 "this.__proto__.y = inc;"
12780 // Invoke it many times to compile a stub
12781 "for (var i = 0; i < 7; i++) {"
12782 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
12784 "this.y = function(x) { return x - 1; };"
12786 "for (var i = 0; i < 7; i++) {"
12787 " result += o.y(42);"
12789 CHECK_EQ(41 * 7, value->Int32Value());
12793 // Test the case when actual function to call sits on global object.
12794 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
12795 v8::Isolate* isolate = CcTest::isolate();
12796 v8::HandleScope scope(isolate);
12797 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12798 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
12800 LocalContext context;
12801 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12803 v8::Handle<Value> value = CompileRun(
12805 " o.__proto__ = this;"
12806 " for (var i = 0; i < 10; i++) {"
12807 " var v = o.parseFloat('239');"
12808 " if (v != 239) throw v;"
12809 // Now it should be ICed and keep a reference to parseFloat.
12812 " for (var i = 0; i < 10; i++) {"
12813 " result += o.parseFloat('239');"
12819 CHECK_EQ(239 * 10, value->Int32Value());
12822 static void InterceptorCallICFastApi(
12823 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
12824 ApiTestFuzzer::Fuzz();
12825 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12827 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12829 if ((*call_count) % 20 == 0) {
12830 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12834 static void FastApiCallback_TrivialSignature(
12835 const v8::FunctionCallbackInfo<v8::Value>& args) {
12836 ApiTestFuzzer::Fuzz();
12837 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12838 v8::Isolate* isolate = CcTest::isolate();
12839 CHECK_EQ(isolate, args.GetIsolate());
12840 CHECK_EQ(args.This(), args.Holder());
12841 CHECK(args.Data()->Equals(v8_str("method_data")));
12842 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12845 static void FastApiCallback_SimpleSignature(
12846 const v8::FunctionCallbackInfo<v8::Value>& args) {
12847 ApiTestFuzzer::Fuzz();
12848 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12849 v8::Isolate* isolate = CcTest::isolate();
12850 CHECK_EQ(isolate, args.GetIsolate());
12851 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12852 CHECK(args.Data()->Equals(v8_str("method_data")));
12853 // Note, we're using HasRealNamedProperty instead of Has to avoid
12854 // invoking the interceptor again.
12855 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12856 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12860 // Helper to maximize the odds of object moving.
12861 static void GenerateSomeGarbage() {
12864 "for (var i = 0; i < 1000; i++) {"
12865 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12867 "garbage = undefined;");
12871 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12872 static int count = 0;
12873 if (count++ % 3 == 0) {
12874 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12875 // This should move the stub
12876 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12881 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12882 LocalContext context;
12883 v8::Isolate* isolate = context->GetIsolate();
12884 v8::HandleScope scope(isolate);
12885 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12886 v8::ObjectTemplate::New(isolate);
12887 nativeobject_templ->Set(isolate, "callback",
12888 v8::FunctionTemplate::New(isolate,
12889 DirectApiCallback));
12890 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12891 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12892 // call the api function multiple times to ensure direct call stub creation.
12895 " for (var i = 1; i <= 30; i++) {"
12896 " nativeobject.callback();"
12903 void ThrowingDirectApiCallback(
12904 const v8::FunctionCallbackInfo<v8::Value>& args) {
12905 args.GetIsolate()->ThrowException(v8_str("g"));
12909 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12910 LocalContext context;
12911 v8::Isolate* isolate = context->GetIsolate();
12912 v8::HandleScope scope(isolate);
12913 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12914 v8::ObjectTemplate::New(isolate);
12915 nativeobject_templ->Set(isolate, "callback",
12916 v8::FunctionTemplate::New(isolate,
12917 ThrowingDirectApiCallback));
12918 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12919 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12920 // call the api function multiple times to ensure direct call stub creation.
12921 v8::Handle<Value> result = CompileRun(
12924 " for (var i = 1; i <= 5; i++) {"
12925 " try { nativeobject.callback(); } catch (e) { result += e; }"
12929 CHECK_EQ(v8_str("ggggg"), result);
12933 static Handle<Value> DoDirectGetter() {
12934 if (++p_getter_count % 3 == 0) {
12935 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12936 GenerateSomeGarbage();
12938 return v8_str("Direct Getter Result");
12941 static void DirectGetterCallback(
12942 Local<String> name,
12943 const v8::PropertyCallbackInfo<v8::Value>& info) {
12944 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12945 info.GetReturnValue().Set(DoDirectGetter());
12949 template<typename Accessor>
12950 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12951 LocalContext context;
12952 v8::Isolate* isolate = context->GetIsolate();
12953 v8::HandleScope scope(isolate);
12954 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12955 obj->SetAccessor(v8_str("p1"), accessor);
12956 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12957 p_getter_count = 0;
12958 v8::Handle<v8::Value> result = CompileRun(
12960 " for (var i = 0; i < 30; i++) o1.p1;"
12964 CHECK_EQ(v8_str("Direct Getter Result"), result);
12965 CHECK_EQ(31, p_getter_count);
12969 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12970 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12974 void ThrowingDirectGetterCallback(
12975 Local<String> name,
12976 const v8::PropertyCallbackInfo<v8::Value>& info) {
12977 info.GetIsolate()->ThrowException(v8_str("g"));
12981 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12982 LocalContext context;
12983 v8::Isolate* isolate = context->GetIsolate();
12984 v8::HandleScope scope(isolate);
12985 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12986 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12987 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12988 v8::Handle<Value> result = CompileRun(
12990 "for (var i = 0; i < 5; i++) {"
12991 " try { o1.p1; } catch (e) { result += e; }"
12994 CHECK_EQ(v8_str("ggggg"), result);
12998 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12999 int interceptor_call_count = 0;
13000 v8::Isolate* isolate = CcTest::isolate();
13001 v8::HandleScope scope(isolate);
13002 v8::Handle<v8::FunctionTemplate> fun_templ =
13003 v8::FunctionTemplate::New(isolate);
13004 v8::Handle<v8::FunctionTemplate> method_templ =
13005 v8::FunctionTemplate::New(isolate,
13006 FastApiCallback_TrivialSignature,
13007 v8_str("method_data"),
13008 v8::Handle<v8::Signature>());
13009 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13010 proto_templ->Set(v8_str("method"), method_templ);
13011 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13012 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13013 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13014 v8::External::New(isolate, &interceptor_call_count)));
13015 LocalContext context;
13016 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13017 GenerateSomeGarbage();
13018 context->Global()->Set(v8_str("o"), fun->NewInstance());
13021 "for (var i = 0; i < 100; i++) {"
13022 " result = o.method(41);"
13024 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13025 CHECK_EQ(100, interceptor_call_count);
13029 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
13030 int interceptor_call_count = 0;
13031 v8::Isolate* isolate = CcTest::isolate();
13032 v8::HandleScope scope(isolate);
13033 v8::Handle<v8::FunctionTemplate> fun_templ =
13034 v8::FunctionTemplate::New(isolate);
13035 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13036 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13037 v8::Signature::New(isolate, fun_templ));
13038 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13039 proto_templ->Set(v8_str("method"), method_templ);
13040 fun_templ->SetHiddenPrototype(true);
13041 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13042 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13043 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13044 v8::External::New(isolate, &interceptor_call_count)));
13045 LocalContext context;
13046 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13047 GenerateSomeGarbage();
13048 context->Global()->Set(v8_str("o"), fun->NewInstance());
13051 "var receiver = {};"
13052 "receiver.__proto__ = o;"
13054 "for (var i = 0; i < 100; i++) {"
13055 " result = receiver.method(41);"
13057 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13058 CHECK_EQ(100, interceptor_call_count);
13062 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
13063 int interceptor_call_count = 0;
13064 v8::Isolate* isolate = CcTest::isolate();
13065 v8::HandleScope scope(isolate);
13066 v8::Handle<v8::FunctionTemplate> fun_templ =
13067 v8::FunctionTemplate::New(isolate);
13068 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13069 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13070 v8::Signature::New(isolate, fun_templ));
13071 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13072 proto_templ->Set(v8_str("method"), method_templ);
13073 fun_templ->SetHiddenPrototype(true);
13074 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13075 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13076 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13077 v8::External::New(isolate, &interceptor_call_count)));
13078 LocalContext context;
13079 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13080 GenerateSomeGarbage();
13081 context->Global()->Set(v8_str("o"), fun->NewInstance());
13084 "var receiver = {};"
13085 "receiver.__proto__ = o;"
13087 "var saved_result = 0;"
13088 "for (var i = 0; i < 100; i++) {"
13089 " result = receiver.method(41);"
13091 " saved_result = result;"
13092 " receiver = {method: function(x) { return x - 1 }};"
13095 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
13096 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13097 CHECK_GE(interceptor_call_count, 50);
13101 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
13102 int interceptor_call_count = 0;
13103 v8::Isolate* isolate = CcTest::isolate();
13104 v8::HandleScope scope(isolate);
13105 v8::Handle<v8::FunctionTemplate> fun_templ =
13106 v8::FunctionTemplate::New(isolate);
13107 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13108 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13109 v8::Signature::New(isolate, fun_templ));
13110 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13111 proto_templ->Set(v8_str("method"), method_templ);
13112 fun_templ->SetHiddenPrototype(true);
13113 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13114 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13115 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13116 v8::External::New(isolate, &interceptor_call_count)));
13117 LocalContext context;
13118 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13119 GenerateSomeGarbage();
13120 context->Global()->Set(v8_str("o"), fun->NewInstance());
13123 "var receiver = {};"
13124 "receiver.__proto__ = o;"
13126 "var saved_result = 0;"
13127 "for (var i = 0; i < 100; i++) {"
13128 " result = receiver.method(41);"
13130 " saved_result = result;"
13131 " o.method = function(x) { return x - 1 };"
13134 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
13135 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13136 CHECK_GE(interceptor_call_count, 50);
13140 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
13141 int interceptor_call_count = 0;
13142 v8::Isolate* isolate = CcTest::isolate();
13143 v8::HandleScope scope(isolate);
13144 v8::Handle<v8::FunctionTemplate> fun_templ =
13145 v8::FunctionTemplate::New(isolate);
13146 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13147 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13148 v8::Signature::New(isolate, fun_templ));
13149 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13150 proto_templ->Set(v8_str("method"), method_templ);
13151 fun_templ->SetHiddenPrototype(true);
13152 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13153 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13154 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13155 v8::External::New(isolate, &interceptor_call_count)));
13156 LocalContext context;
13157 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13158 GenerateSomeGarbage();
13159 context->Global()->Set(v8_str("o"), fun->NewInstance());
13160 v8::TryCatch try_catch;
13163 "var receiver = {};"
13164 "receiver.__proto__ = o;"
13166 "var saved_result = 0;"
13167 "for (var i = 0; i < 100; i++) {"
13168 " result = receiver.method(41);"
13170 " saved_result = result;"
13174 CHECK(try_catch.HasCaught());
13175 // TODO(verwaest): Adjust message.
13176 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
13177 try_catch.Exception()->ToString(isolate));
13178 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13179 CHECK_GE(interceptor_call_count, 50);
13183 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
13184 int interceptor_call_count = 0;
13185 v8::Isolate* isolate = CcTest::isolate();
13186 v8::HandleScope scope(isolate);
13187 v8::Handle<v8::FunctionTemplate> fun_templ =
13188 v8::FunctionTemplate::New(isolate);
13189 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13190 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13191 v8::Signature::New(isolate, fun_templ));
13192 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13193 proto_templ->Set(v8_str("method"), method_templ);
13194 fun_templ->SetHiddenPrototype(true);
13195 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
13196 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13197 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
13198 v8::External::New(isolate, &interceptor_call_count)));
13199 LocalContext context;
13200 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13201 GenerateSomeGarbage();
13202 context->Global()->Set(v8_str("o"), fun->NewInstance());
13203 v8::TryCatch try_catch;
13206 "var receiver = {};"
13207 "receiver.__proto__ = o;"
13209 "var saved_result = 0;"
13210 "for (var i = 0; i < 100; i++) {"
13211 " result = receiver.method(41);"
13213 " saved_result = result;"
13214 " receiver = {method: receiver.method};"
13217 CHECK(try_catch.HasCaught());
13218 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
13219 try_catch.Exception()->ToString(isolate));
13220 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13221 CHECK_GE(interceptor_call_count, 50);
13225 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
13226 v8::Isolate* isolate = CcTest::isolate();
13227 v8::HandleScope scope(isolate);
13228 v8::Handle<v8::FunctionTemplate> fun_templ =
13229 v8::FunctionTemplate::New(isolate);
13230 v8::Handle<v8::FunctionTemplate> method_templ =
13231 v8::FunctionTemplate::New(isolate,
13232 FastApiCallback_TrivialSignature,
13233 v8_str("method_data"),
13234 v8::Handle<v8::Signature>());
13235 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13236 proto_templ->Set(v8_str("method"), method_templ);
13237 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13239 LocalContext context;
13240 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13241 GenerateSomeGarbage();
13242 context->Global()->Set(v8_str("o"), fun->NewInstance());
13245 "for (var i = 0; i < 100; i++) {"
13246 " result = o.method(41);"
13249 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13253 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
13254 v8::Isolate* isolate = CcTest::isolate();
13255 v8::HandleScope scope(isolate);
13256 v8::Handle<v8::FunctionTemplate> fun_templ =
13257 v8::FunctionTemplate::New(isolate);
13258 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13259 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13260 v8::Signature::New(isolate, fun_templ));
13261 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13262 proto_templ->Set(v8_str("method"), method_templ);
13263 fun_templ->SetHiddenPrototype(true);
13264 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13265 CHECK(!templ.IsEmpty());
13266 LocalContext context;
13267 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13268 GenerateSomeGarbage();
13269 context->Global()->Set(v8_str("o"), fun->NewInstance());
13272 "var receiver = {};"
13273 "receiver.__proto__ = o;"
13275 "for (var i = 0; i < 100; i++) {"
13276 " result = receiver.method(41);"
13279 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
13283 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
13284 v8::Isolate* isolate = CcTest::isolate();
13285 v8::HandleScope scope(isolate);
13286 v8::Handle<v8::FunctionTemplate> fun_templ =
13287 v8::FunctionTemplate::New(isolate);
13288 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13289 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13290 v8::Signature::New(isolate, fun_templ));
13291 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13292 proto_templ->Set(v8_str("method"), method_templ);
13293 fun_templ->SetHiddenPrototype(true);
13294 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13295 CHECK(!templ.IsEmpty());
13296 LocalContext context;
13297 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13298 GenerateSomeGarbage();
13299 context->Global()->Set(v8_str("o"), fun->NewInstance());
13302 "var receiver = {};"
13303 "receiver.__proto__ = o;"
13305 "var saved_result = 0;"
13306 "for (var i = 0; i < 100; i++) {"
13307 " result = receiver.method(41);"
13309 " saved_result = result;"
13310 " receiver = {method: function(x) { return x - 1 }};"
13313 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
13314 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13318 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
13319 v8::Isolate* isolate = CcTest::isolate();
13320 v8::HandleScope scope(isolate);
13321 v8::Handle<v8::FunctionTemplate> fun_templ =
13322 v8::FunctionTemplate::New(isolate);
13323 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13324 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13325 v8::Signature::New(isolate, fun_templ));
13326 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13327 proto_templ->Set(v8_str("method"), method_templ);
13328 fun_templ->SetHiddenPrototype(true);
13329 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13330 CHECK(!templ.IsEmpty());
13331 LocalContext context;
13332 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13333 GenerateSomeGarbage();
13334 context->Global()->Set(v8_str("o"), fun->NewInstance());
13335 v8::TryCatch try_catch;
13338 "var receiver = {};"
13339 "receiver.__proto__ = o;"
13341 "var saved_result = 0;"
13342 "for (var i = 0; i < 100; i++) {"
13343 " result = receiver.method(41);"
13345 " saved_result = result;"
13349 CHECK(try_catch.HasCaught());
13350 // TODO(verwaest): Adjust message.
13351 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
13352 try_catch.Exception()->ToString(isolate));
13353 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13357 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
13358 v8::Isolate* isolate = CcTest::isolate();
13359 v8::HandleScope scope(isolate);
13360 v8::Handle<v8::FunctionTemplate> fun_templ =
13361 v8::FunctionTemplate::New(isolate);
13362 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13363 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13364 v8::Signature::New(isolate, fun_templ));
13365 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13366 proto_templ->Set(v8_str("method"), method_templ);
13367 fun_templ->SetHiddenPrototype(true);
13368 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13369 CHECK(!templ.IsEmpty());
13370 LocalContext context;
13371 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13372 GenerateSomeGarbage();
13373 context->Global()->Set(v8_str("o"), fun->NewInstance());
13374 v8::TryCatch try_catch;
13377 "var receiver = {};"
13378 "receiver.__proto__ = o;"
13380 "var saved_result = 0;"
13381 "for (var i = 0; i < 100; i++) {"
13382 " result = receiver.method(41);"
13384 " saved_result = result;"
13385 " receiver = Object.create(receiver);"
13388 CHECK(try_catch.HasCaught());
13389 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
13390 try_catch.Exception()->ToString(isolate));
13391 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13395 v8::Handle<Value> keyed_call_ic_function;
13397 static void InterceptorKeyedCallICGetter(
13398 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13399 ApiTestFuzzer::Fuzz();
13400 if (v8_str("x")->Equals(name)) {
13401 info.GetReturnValue().Set(keyed_call_ic_function);
13406 // Test the case when we stored cacheable lookup into
13407 // a stub, but the function name changed (to another cacheable function).
13408 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
13409 v8::Isolate* isolate = CcTest::isolate();
13410 v8::HandleScope scope(isolate);
13411 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13412 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
13413 LocalContext context;
13414 context->Global()->Set(v8_str("o"), templ->NewInstance());
13416 "proto = new Object();"
13417 "proto.y = function(x) { return x + 1; };"
13418 "proto.z = function(x) { return x - 1; };"
13419 "o.__proto__ = proto;"
13421 "var method = 'y';"
13422 "for (var i = 0; i < 10; i++) {"
13423 " if (i == 5) { method = 'z'; };"
13424 " result += o[method](41);"
13426 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13430 // Test the case when we stored cacheable lookup into
13431 // a stub, but the function name changed (and the new function is present
13432 // both before and after the interceptor in the prototype chain).
13433 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
13434 v8::Isolate* isolate = CcTest::isolate();
13435 v8::HandleScope scope(isolate);
13436 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13438 v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
13439 LocalContext context;
13440 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
13441 keyed_call_ic_function =
13442 v8_compile("function f(x) { return x - 1; }; f")->Run();
13444 "o = new Object();"
13445 "proto2 = new Object();"
13446 "o.y = function(x) { return x + 1; };"
13447 "proto2.y = function(x) { return x + 2; };"
13448 "o.__proto__ = proto1;"
13449 "proto1.__proto__ = proto2;"
13451 "var method = 'x';"
13452 "for (var i = 0; i < 10; i++) {"
13453 " if (i == 5) { method = 'y'; };"
13454 " result += o[method](41);"
13456 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13460 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
13461 // on the global object.
13462 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
13463 v8::Isolate* isolate = CcTest::isolate();
13464 v8::HandleScope scope(isolate);
13465 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13466 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
13467 LocalContext context;
13468 context->Global()->Set(v8_str("o"), templ->NewInstance());
13470 "function inc(x) { return x + 1; };"
13472 "function dec(x) { return x - 1; };"
13474 "o.__proto__ = this;"
13475 "this.__proto__.x = inc;"
13476 "this.__proto__.y = dec;"
13478 "var method = 'x';"
13479 "for (var i = 0; i < 10; i++) {"
13480 " if (i == 5) { method = 'y'; };"
13481 " result += o[method](41);"
13483 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13487 // Test the case when actual function to call sits on global object.
13488 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
13489 v8::Isolate* isolate = CcTest::isolate();
13490 v8::HandleScope scope(isolate);
13491 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13492 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
13493 LocalContext context;
13494 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
13497 "function len(x) { return x.length; };"
13498 "o.__proto__ = this;"
13499 "var m = 'parseFloat';"
13501 "for (var i = 0; i < 10; i++) {"
13504 " saved_result = result;"
13506 " result = o[m]('239');"
13508 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
13509 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13513 // Test the map transition before the interceptor.
13514 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
13515 v8::Isolate* isolate = CcTest::isolate();
13516 v8::HandleScope scope(isolate);
13517 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13518 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
13519 LocalContext context;
13520 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
13523 "var o = new Object();"
13524 "o.__proto__ = proto;"
13525 "o.method = function(x) { return x + 1; };"
13526 "var m = 'method';"
13528 "for (var i = 0; i < 10; i++) {"
13529 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
13530 " result += o[m](41);"
13532 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13536 // Test the map transition after the interceptor.
13537 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
13538 v8::Isolate* isolate = CcTest::isolate();
13539 v8::HandleScope scope(isolate);
13540 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13541 templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
13542 LocalContext context;
13543 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
13546 "var proto = new Object();"
13547 "o.__proto__ = proto;"
13548 "proto.method = function(x) { return x + 1; };"
13549 "var m = 'method';"
13551 "for (var i = 0; i < 10; i++) {"
13552 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
13553 " result += o[m](41);"
13555 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13559 static int interceptor_call_count = 0;
13561 static void InterceptorICRefErrorGetter(
13562 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13563 ApiTestFuzzer::Fuzz();
13564 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
13565 info.GetReturnValue().Set(call_ic_function2);
13570 // This test should hit load and call ICs for the interceptor case.
13571 // Once in a while, the interceptor will reply that a property was not
13572 // found in which case we should get a reference error.
13573 THREADED_TEST(InterceptorICReferenceErrors) {
13574 v8::Isolate* isolate = CcTest::isolate();
13575 v8::HandleScope scope(isolate);
13576 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13578 v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
13579 LocalContext context(0, templ, v8::Handle<Value>());
13580 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
13581 v8::Handle<Value> value = CompileRun(
13583 " for (var i = 0; i < 1000; i++) {"
13584 " try { x; } catch(e) { return true; }"
13589 CHECK_EQ(true, value->BooleanValue());
13590 interceptor_call_count = 0;
13591 value = CompileRun(
13593 " for (var i = 0; i < 1000; i++) {"
13594 " try { x(42); } catch(e) { return true; }"
13599 CHECK_EQ(true, value->BooleanValue());
13603 static int interceptor_ic_exception_get_count = 0;
13605 static void InterceptorICExceptionGetter(
13606 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
13607 ApiTestFuzzer::Fuzz();
13608 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
13609 info.GetReturnValue().Set(call_ic_function3);
13611 if (interceptor_ic_exception_get_count == 20) {
13612 info.GetIsolate()->ThrowException(v8_num(42));
13618 // Test interceptor load/call IC where the interceptor throws an
13619 // exception once in a while.
13620 THREADED_TEST(InterceptorICGetterExceptions) {
13621 interceptor_ic_exception_get_count = 0;
13622 v8::Isolate* isolate = CcTest::isolate();
13623 v8::HandleScope scope(isolate);
13624 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13626 v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
13627 LocalContext context(0, templ, v8::Handle<Value>());
13628 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
13629 v8::Handle<Value> value = CompileRun(
13631 " for (var i = 0; i < 100; i++) {"
13632 " try { x; } catch(e) { return true; }"
13637 CHECK_EQ(true, value->BooleanValue());
13638 interceptor_ic_exception_get_count = 0;
13639 value = CompileRun(
13641 " for (var i = 0; i < 100; i++) {"
13642 " try { x(42); } catch(e) { return true; }"
13647 CHECK_EQ(true, value->BooleanValue());
13651 static int interceptor_ic_exception_set_count = 0;
13653 static void InterceptorICExceptionSetter(
13654 Local<Name> key, Local<Value> value,
13655 const v8::PropertyCallbackInfo<v8::Value>& info) {
13656 ApiTestFuzzer::Fuzz();
13657 if (++interceptor_ic_exception_set_count > 20) {
13658 info.GetIsolate()->ThrowException(v8_num(42));
13663 // Test interceptor store IC where the interceptor throws an exception
13664 // once in a while.
13665 THREADED_TEST(InterceptorICSetterExceptions) {
13666 interceptor_ic_exception_set_count = 0;
13667 v8::Isolate* isolate = CcTest::isolate();
13668 v8::HandleScope scope(isolate);
13669 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13671 v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
13672 LocalContext context(0, templ, v8::Handle<Value>());
13673 v8::Handle<Value> value = CompileRun(
13675 " for (var i = 0; i < 100; i++) {"
13676 " try { x = 42; } catch(e) { return true; }"
13681 CHECK_EQ(true, value->BooleanValue());
13685 // Test that we ignore null interceptors.
13686 THREADED_TEST(NullNamedInterceptor) {
13687 v8::Isolate* isolate = CcTest::isolate();
13688 v8::HandleScope scope(isolate);
13689 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13690 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
13691 static_cast<v8::GenericNamedPropertyGetterCallback>(0)));
13692 LocalContext context;
13693 templ->Set(CcTest::isolate(), "x", v8_num(42));
13694 v8::Handle<v8::Object> obj = templ->NewInstance();
13695 context->Global()->Set(v8_str("obj"), obj);
13696 v8::Handle<Value> value = CompileRun("obj.x");
13697 CHECK(value->IsInt32());
13698 CHECK_EQ(42, value->Int32Value());
13702 // Test that we ignore null interceptors.
13703 THREADED_TEST(NullIndexedInterceptor) {
13704 v8::Isolate* isolate = CcTest::isolate();
13705 v8::HandleScope scope(isolate);
13706 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13707 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
13708 static_cast<v8::IndexedPropertyGetterCallback>(0)));
13709 LocalContext context;
13710 templ->Set(CcTest::isolate(), "42", v8_num(42));
13711 v8::Handle<v8::Object> obj = templ->NewInstance();
13712 context->Global()->Set(v8_str("obj"), obj);
13713 v8::Handle<Value> value = CompileRun("obj[42]");
13714 CHECK(value->IsInt32());
13715 CHECK_EQ(42, value->Int32Value());
13719 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
13720 v8::Isolate* isolate = CcTest::isolate();
13721 v8::HandleScope scope(isolate);
13722 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13723 templ->InstanceTemplate()->SetHandler(
13724 v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
13726 env->Global()->Set(v8_str("obj"),
13727 templ->GetFunction()->NewInstance());
13728 ExpectTrue("obj.x === 42");
13729 ExpectTrue("!obj.propertyIsEnumerable('x')");
13733 static void ThrowingGetter(Local<String> name,
13734 const v8::PropertyCallbackInfo<v8::Value>& info) {
13735 ApiTestFuzzer::Fuzz();
13736 info.GetIsolate()->ThrowException(Handle<Value>());
13737 info.GetReturnValue().SetUndefined();
13741 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
13742 LocalContext context;
13743 HandleScope scope(context->GetIsolate());
13745 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
13746 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13747 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
13749 Local<Object> instance = templ->GetFunction()->NewInstance();
13751 Local<Object> another = Object::New(context->GetIsolate());
13752 another->SetPrototype(instance);
13754 Local<Object> with_js_getter = CompileRun(
13756 "o.__defineGetter__('f', function() { throw undefined; });\n"
13757 "o\n").As<Object>();
13758 CHECK(!with_js_getter.IsEmpty());
13760 TryCatch try_catch;
13762 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
13763 CHECK(try_catch.HasCaught());
13765 CHECK(result.IsEmpty());
13767 result = another->GetRealNamedProperty(v8_str("f"));
13768 CHECK(try_catch.HasCaught());
13770 CHECK(result.IsEmpty());
13772 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
13773 CHECK(try_catch.HasCaught());
13775 CHECK(result.IsEmpty());
13777 result = another->Get(v8_str("f"));
13778 CHECK(try_catch.HasCaught());
13780 CHECK(result.IsEmpty());
13782 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
13783 CHECK(try_catch.HasCaught());
13785 CHECK(result.IsEmpty());
13787 result = with_js_getter->Get(v8_str("f"));
13788 CHECK(try_catch.HasCaught());
13790 CHECK(result.IsEmpty());
13794 static void ThrowingCallbackWithTryCatch(
13795 const v8::FunctionCallbackInfo<v8::Value>& args) {
13796 TryCatch try_catch;
13797 // Verboseness is important: it triggers message delivery which can call into
13799 try_catch.SetVerbose(true);
13800 CompileRun("throw 'from JS';");
13801 CHECK(try_catch.HasCaught());
13802 CHECK(!CcTest::i_isolate()->has_pending_exception());
13803 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13807 static int call_depth;
13810 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13811 TryCatch try_catch;
13815 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13816 if (--call_depth) CompileRun("throw 'ThrowInJS';");
13820 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13821 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13825 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13826 Handle<String> errorMessageString = message->Get();
13827 CHECK(!errorMessageString.IsEmpty());
13828 message->GetStackTrace();
13829 message->GetScriptOrigin().ResourceName();
13833 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13834 LocalContext context;
13835 v8::Isolate* isolate = context->GetIsolate();
13836 HandleScope scope(isolate);
13838 Local<Function> func =
13839 FunctionTemplate::New(isolate,
13840 ThrowingCallbackWithTryCatch)->GetFunction();
13841 context->Global()->Set(v8_str("func"), func);
13843 MessageCallback callbacks[] =
13844 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13845 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13846 MessageCallback callback = callbacks[i];
13847 if (callback != NULL) {
13848 V8::AddMessageListener(callback);
13850 // Some small number to control number of times message handler should
13851 // throw an exception.
13854 "var thrown = false;\n"
13855 "try { func(); } catch(e) { thrown = true; }\n"
13857 if (callback != NULL) {
13858 V8::RemoveMessageListeners(callback);
13864 static void ParentGetter(Local<String> name,
13865 const v8::PropertyCallbackInfo<v8::Value>& info) {
13866 ApiTestFuzzer::Fuzz();
13867 info.GetReturnValue().Set(v8_num(1));
13871 static void ChildGetter(Local<String> name,
13872 const v8::PropertyCallbackInfo<v8::Value>& info) {
13873 ApiTestFuzzer::Fuzz();
13874 info.GetReturnValue().Set(v8_num(42));
13878 THREADED_TEST(Overriding) {
13879 LocalContext context;
13880 v8::Isolate* isolate = context->GetIsolate();
13881 v8::HandleScope scope(isolate);
13883 // Parent template.
13884 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13885 Local<ObjectTemplate> parent_instance_templ =
13886 parent_templ->InstanceTemplate();
13887 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13889 // Template that inherits from the parent template.
13890 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13891 Local<ObjectTemplate> child_instance_templ =
13892 child_templ->InstanceTemplate();
13893 child_templ->Inherit(parent_templ);
13894 // Override 'f'. The child version of 'f' should get called for child
13896 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13897 // Add 'g' twice. The 'g' added last should get called for instances.
13898 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13899 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13901 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13902 // so 'h' can be shadowed on the instance object.
13903 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13904 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13905 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13907 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13908 // but the attribute does not have effect because it is duplicated with
13910 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13911 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13915 // Instantiate the child template.
13916 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13918 // Check that the child function overrides the parent one.
13919 context->Global()->Set(v8_str("o"), instance);
13920 Local<Value> value = v8_compile("o.f")->Run();
13921 // Check that the 'g' that was added last is hit.
13922 CHECK_EQ(42, value->Int32Value());
13923 value = v8_compile("o.g")->Run();
13924 CHECK_EQ(42, value->Int32Value());
13926 // Check that 'h' cannot be shadowed.
13927 value = v8_compile("o.h = 3; o.h")->Run();
13928 CHECK_EQ(1, value->Int32Value());
13930 // Check that 'i' cannot be shadowed or changed.
13931 value = v8_compile("o.i = 3; o.i")->Run();
13932 CHECK_EQ(42, value->Int32Value());
13936 static void IsConstructHandler(
13937 const v8::FunctionCallbackInfo<v8::Value>& args) {
13938 ApiTestFuzzer::Fuzz();
13939 args.GetReturnValue().Set(args.IsConstructCall());
13943 THREADED_TEST(IsConstructCall) {
13944 v8::Isolate* isolate = CcTest::isolate();
13945 v8::HandleScope scope(isolate);
13947 // Function template with call handler.
13948 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13949 templ->SetCallHandler(IsConstructHandler);
13951 LocalContext context;
13953 context->Global()->Set(v8_str("f"), templ->GetFunction());
13954 Local<Value> value = v8_compile("f()")->Run();
13955 CHECK(!value->BooleanValue());
13956 value = v8_compile("new f()")->Run();
13957 CHECK(value->BooleanValue());
13961 THREADED_TEST(ObjectProtoToString) {
13962 v8::Isolate* isolate = CcTest::isolate();
13963 v8::HandleScope scope(isolate);
13964 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13965 templ->SetClassName(v8_str("MyClass"));
13967 LocalContext context;
13969 Local<String> customized_tostring = v8_str("customized toString");
13971 // Replace Object.prototype.toString
13972 v8_compile("Object.prototype.toString = function() {"
13973 " return 'customized toString';"
13976 // Normal ToString call should call replaced Object.prototype.toString
13977 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13978 Local<String> value = instance->ToString(isolate);
13979 CHECK(value->IsString() && value->Equals(customized_tostring));
13981 // ObjectProtoToString should not call replace toString function.
13982 value = instance->ObjectProtoToString();
13983 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13986 value = context->Global()->ObjectProtoToString();
13987 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13989 // Check ordinary object
13990 Local<Value> object = v8_compile("new Object()")->Run();
13991 value = object.As<v8::Object>()->ObjectProtoToString();
13992 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13996 TEST(ObjectProtoToStringES6) {
13997 // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
13998 i::FLAG_harmony_tostring = true;
13999 LocalContext context;
14000 v8::Isolate* isolate = CcTest::isolate();
14001 v8::HandleScope scope(isolate);
14002 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
14003 templ->SetClassName(v8_str("MyClass"));
14005 Local<String> customized_tostring = v8_str("customized toString");
14007 // Replace Object.prototype.toString
14009 "Object.prototype.toString = function() {"
14010 " return 'customized toString';"
14013 // Normal ToString call should call replaced Object.prototype.toString
14014 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
14015 Local<String> value = instance->ToString(isolate);
14016 CHECK(value->IsString() && value->Equals(customized_tostring));
14018 // ObjectProtoToString should not call replace toString function.
14019 value = instance->ObjectProtoToString();
14020 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
14023 value = context->Global()->ObjectProtoToString();
14024 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
14026 // Check ordinary object
14027 Local<Value> object = CompileRun("new Object()");
14028 value = object.As<v8::Object>()->ObjectProtoToString();
14029 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
14031 // Check that ES6 semantics using @@toStringTag work
14032 Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
14034 #define TEST_TOSTRINGTAG(type, tag, expected) \
14036 object = CompileRun("new " #type "()"); \
14037 object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
14038 value = object.As<v8::Object>()->ObjectProtoToString(); \
14039 CHECK(value->IsString() && \
14040 value->Equals(v8_str("[object " #expected "]"))); \
14043 TEST_TOSTRINGTAG(Array, Object, Object);
14044 TEST_TOSTRINGTAG(Object, Arguments, ~Arguments);
14045 TEST_TOSTRINGTAG(Object, Array, ~Array);
14046 TEST_TOSTRINGTAG(Object, Boolean, ~Boolean);
14047 TEST_TOSTRINGTAG(Object, Date, ~Date);
14048 TEST_TOSTRINGTAG(Object, Error, ~Error);
14049 TEST_TOSTRINGTAG(Object, Function, ~Function);
14050 TEST_TOSTRINGTAG(Object, Number, ~Number);
14051 TEST_TOSTRINGTAG(Object, RegExp, ~RegExp);
14052 TEST_TOSTRINGTAG(Object, String, ~String);
14053 TEST_TOSTRINGTAG(Object, Foo, Foo);
14055 #undef TEST_TOSTRINGTAG
14057 // @@toStringTag getter throws
14058 Local<Value> obj = v8::Object::New(isolate);
14059 obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
14061 TryCatch try_catch;
14062 value = obj.As<v8::Object>()->ObjectProtoToString();
14063 CHECK(value.IsEmpty());
14064 CHECK(try_catch.HasCaught());
14067 // @@toStringTag getter does not throw
14068 obj = v8::Object::New(isolate);
14069 obj.As<v8::Object>()->SetAccessor(
14070 toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
14072 TryCatch try_catch;
14073 value = obj.As<v8::Object>()->ObjectProtoToString();
14074 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
14075 CHECK(!try_catch.HasCaught());
14078 // JS @@toStringTag value
14079 obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
14081 TryCatch try_catch;
14082 value = obj.As<v8::Object>()->ObjectProtoToString();
14083 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
14084 CHECK(!try_catch.HasCaught());
14087 // JS @@toStringTag getter throws
14089 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
14090 " get: function() { throw 'Test'; }"
14093 TryCatch try_catch;
14094 value = obj.As<v8::Object>()->ObjectProtoToString();
14095 CHECK(value.IsEmpty());
14096 CHECK(try_catch.HasCaught());
14099 // JS @@toStringTag getter does not throw
14101 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
14102 " get: function() { return 'Test'; }"
14105 TryCatch try_catch;
14106 value = obj.As<v8::Object>()->ObjectProtoToString();
14107 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
14108 CHECK(!try_catch.HasCaught());
14113 THREADED_TEST(ObjectGetConstructorName) {
14114 v8::Isolate* isolate = CcTest::isolate();
14115 LocalContext context;
14116 v8::HandleScope scope(isolate);
14117 v8_compile("function Parent() {};"
14118 "function Child() {};"
14119 "Child.prototype = new Parent();"
14120 "var outer = { inner: function() { } };"
14121 "var p = new Parent();"
14122 "var c = new Child();"
14123 "var x = new outer.inner();")->Run();
14125 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
14126 CHECK(p->IsObject() &&
14127 p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
14129 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
14130 CHECK(c->IsObject() &&
14131 c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
14133 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
14134 CHECK(x->IsObject() &&
14135 x->ToObject(isolate)->GetConstructorName()->Equals(
14136 v8_str("outer.inner")));
14140 bool ApiTestFuzzer::fuzzing_ = false;
14141 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
14142 int ApiTestFuzzer::active_tests_;
14143 int ApiTestFuzzer::tests_being_run_;
14144 int ApiTestFuzzer::current_;
14147 // We are in a callback and want to switch to another thread (if we
14148 // are currently running the thread fuzzing test).
14149 void ApiTestFuzzer::Fuzz() {
14150 if (!fuzzing_) return;
14151 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
14152 test->ContextSwitch();
14156 // Let the next thread go. Since it is also waiting on the V8 lock it may
14157 // not start immediately.
14158 bool ApiTestFuzzer::NextThread() {
14159 int test_position = GetNextTestNumber();
14160 const char* test_name = RegisterThreadedTest::nth(current_)->name();
14161 if (test_position == current_) {
14163 printf("Stay with %s\n", test_name);
14166 if (kLogThreading) {
14167 printf("Switch from %s to %s\n",
14169 RegisterThreadedTest::nth(test_position)->name());
14171 current_ = test_position;
14172 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
14177 void ApiTestFuzzer::Run() {
14178 // When it is our turn...
14181 // ... get the V8 lock and start running the test.
14182 v8::Locker locker(CcTest::isolate());
14185 // This test finished.
14188 // If it was the last then signal that fact.
14189 if (active_tests_ == 0) {
14190 all_tests_done_.Signal();
14192 // Otherwise select a new test and start that.
14198 static unsigned linear_congruential_generator;
14201 void ApiTestFuzzer::SetUp(PartOfTest part) {
14202 linear_congruential_generator = i::FLAG_testing_prng_seed;
14204 int count = RegisterThreadedTest::count();
14205 int start = count * part / (LAST_PART + 1);
14206 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
14207 active_tests_ = tests_being_run_ = end - start + 1;
14208 for (int i = 0; i < tests_being_run_; i++) {
14209 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
14211 for (int i = 0; i < active_tests_; i++) {
14212 RegisterThreadedTest::nth(i)->fuzzer_->Start();
14217 static void CallTestNumber(int test_number) {
14218 (RegisterThreadedTest::nth(test_number)->callback())();
14222 void ApiTestFuzzer::RunAllTests() {
14223 // Set off the first test.
14226 // Wait till they are all done.
14227 all_tests_done_.Wait();
14231 int ApiTestFuzzer::GetNextTestNumber() {
14234 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
14235 linear_congruential_generator *= 1664525u;
14236 linear_congruential_generator += 1013904223u;
14237 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
14242 void ApiTestFuzzer::ContextSwitch() {
14243 // If the new thread is the same as the current thread there is nothing to do.
14244 if (NextThread()) {
14245 // Now it can start.
14246 v8::Unlocker unlocker(CcTest::isolate());
14247 // Wait till someone starts us again.
14254 void ApiTestFuzzer::TearDown() {
14256 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
14257 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
14258 if (fuzzer != NULL) fuzzer->Join();
14263 // Lets not be needlessly self-referential.
14265 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
14266 ApiTestFuzzer::RunAllTests();
14267 ApiTestFuzzer::TearDown();
14272 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
14273 ApiTestFuzzer::RunAllTests();
14274 ApiTestFuzzer::TearDown();
14279 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
14280 ApiTestFuzzer::RunAllTests();
14281 ApiTestFuzzer::TearDown();
14286 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
14287 ApiTestFuzzer::RunAllTests();
14288 ApiTestFuzzer::TearDown();
14292 void ApiTestFuzzer::CallTest() {
14293 v8::Isolate::Scope scope(CcTest::isolate());
14295 printf("Start test %d\n", test_number_);
14296 CallTestNumber(test_number_);
14298 printf("End test %d\n", test_number_);
14302 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
14303 v8::Isolate* isolate = args.GetIsolate();
14304 CHECK(v8::Locker::IsLocked(isolate));
14305 ApiTestFuzzer::Fuzz();
14306 v8::Unlocker unlocker(isolate);
14307 const char* code = "throw 7;";
14309 v8::Locker nested_locker(isolate);
14310 v8::HandleScope scope(isolate);
14311 v8::Handle<Value> exception;
14312 { v8::TryCatch try_catch;
14313 v8::Handle<Value> value = CompileRun(code);
14314 CHECK(value.IsEmpty());
14315 CHECK(try_catch.HasCaught());
14316 // Make sure to wrap the exception in a new handle because
14317 // the handle returned from the TryCatch is destroyed
14318 // when the TryCatch is destroyed.
14319 exception = Local<Value>::New(isolate, try_catch.Exception());
14321 args.GetIsolate()->ThrowException(exception);
14326 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
14327 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
14328 ApiTestFuzzer::Fuzz();
14329 v8::Unlocker unlocker(CcTest::isolate());
14330 const char* code = "throw 7;";
14332 v8::Locker nested_locker(CcTest::isolate());
14333 v8::HandleScope scope(args.GetIsolate());
14334 v8::Handle<Value> value = CompileRun(code);
14335 CHECK(value.IsEmpty());
14336 args.GetReturnValue().Set(v8_str("foo"));
14341 // These are locking tests that don't need to be run again
14342 // as part of the locking aggregation tests.
14343 TEST(NestedLockers) {
14344 v8::Isolate* isolate = CcTest::isolate();
14345 v8::Locker locker(isolate);
14346 CHECK(v8::Locker::IsLocked(isolate));
14348 v8::HandleScope scope(env->GetIsolate());
14349 Local<v8::FunctionTemplate> fun_templ =
14350 v8::FunctionTemplate::New(isolate, ThrowInJS);
14351 Local<Function> fun = fun_templ->GetFunction();
14352 env->Global()->Set(v8_str("throw_in_js"), fun);
14353 Local<Script> script = v8_compile("(function () {"
14361 CHECK_EQ(91, script->Run()->Int32Value());
14365 // These are locking tests that don't need to be run again
14366 // as part of the locking aggregation tests.
14367 TEST(NestedLockersNoTryCatch) {
14368 v8::Locker locker(CcTest::isolate());
14370 v8::HandleScope scope(env->GetIsolate());
14371 Local<v8::FunctionTemplate> fun_templ =
14372 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
14373 Local<Function> fun = fun_templ->GetFunction();
14374 env->Global()->Set(v8_str("throw_in_js"), fun);
14375 Local<Script> script = v8_compile("(function () {"
14383 CHECK_EQ(91, script->Run()->Int32Value());
14387 THREADED_TEST(RecursiveLocking) {
14388 v8::Locker locker(CcTest::isolate());
14390 v8::Locker locker2(CcTest::isolate());
14391 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
14396 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
14397 ApiTestFuzzer::Fuzz();
14398 v8::Unlocker unlocker(CcTest::isolate());
14402 THREADED_TEST(LockUnlockLock) {
14404 v8::Locker locker(CcTest::isolate());
14405 v8::HandleScope scope(CcTest::isolate());
14407 Local<v8::FunctionTemplate> fun_templ =
14408 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
14409 Local<Function> fun = fun_templ->GetFunction();
14410 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
14411 Local<Script> script = v8_compile("(function () {"
14412 " unlock_for_a_moment();"
14415 CHECK_EQ(42, script->Run()->Int32Value());
14418 v8::Locker locker(CcTest::isolate());
14419 v8::HandleScope scope(CcTest::isolate());
14421 Local<v8::FunctionTemplate> fun_templ =
14422 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
14423 Local<Function> fun = fun_templ->GetFunction();
14424 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
14425 Local<Script> script = v8_compile("(function () {"
14426 " unlock_for_a_moment();"
14429 CHECK_EQ(42, script->Run()->Int32Value());
14434 static int GetGlobalObjectsCount() {
14436 i::HeapIterator it(CcTest::heap());
14437 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
14438 if (object->IsJSGlobalObject()) count++;
14443 static void CheckSurvivingGlobalObjectsCount(int expected) {
14444 // We need to collect all garbage twice to be sure that everything
14445 // has been collected. This is because inline caches are cleared in
14446 // the first garbage collection but some of the maps have already
14447 // been marked at that point. Therefore some of the maps are not
14448 // collected until the second garbage collection.
14449 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14450 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
14451 int count = GetGlobalObjectsCount();
14453 if (count != expected) CcTest::heap()->TracePathToGlobal();
14455 CHECK_EQ(expected, count);
14459 TEST(DontLeakGlobalObjects) {
14460 // Regression test for issues 1139850 and 1174891.
14462 i::FLAG_expose_gc = true;
14463 v8::V8::Initialize();
14465 for (int i = 0; i < 5; i++) {
14466 { v8::HandleScope scope(CcTest::isolate());
14467 LocalContext context;
14469 CcTest::isolate()->ContextDisposedNotification();
14470 CheckSurvivingGlobalObjectsCount(0);
14472 { v8::HandleScope scope(CcTest::isolate());
14473 LocalContext context;
14474 v8_compile("Date")->Run();
14476 CcTest::isolate()->ContextDisposedNotification();
14477 CheckSurvivingGlobalObjectsCount(0);
14479 { v8::HandleScope scope(CcTest::isolate());
14480 LocalContext context;
14481 v8_compile("/aaa/")->Run();
14483 CcTest::isolate()->ContextDisposedNotification();
14484 CheckSurvivingGlobalObjectsCount(0);
14486 { v8::HandleScope scope(CcTest::isolate());
14487 const char* extension_list[] = { "v8/gc" };
14488 v8::ExtensionConfiguration extensions(1, extension_list);
14489 LocalContext context(&extensions);
14490 v8_compile("gc();")->Run();
14492 CcTest::isolate()->ContextDisposedNotification();
14493 CheckSurvivingGlobalObjectsCount(0);
14498 TEST(CopyablePersistent) {
14499 LocalContext context;
14500 v8::Isolate* isolate = context->GetIsolate();
14501 i::GlobalHandles* globals =
14502 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14503 int initial_handles = globals->global_handles_count();
14504 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
14507 CopyableObject handle1;
14509 v8::HandleScope scope(isolate);
14510 handle1.Reset(isolate, v8::Object::New(isolate));
14512 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
14513 CopyableObject handle2;
14515 CHECK(handle1 == handle2);
14516 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
14517 CopyableObject handle3(handle2);
14518 CHECK(handle1 == handle3);
14519 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
14521 // Verify autodispose
14522 CHECK_EQ(initial_handles, globals->global_handles_count());
14526 static void WeakApiCallback(
14527 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
14528 Local<Value> value = data.GetValue()->Get(v8_str("key"));
14529 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
14530 data.GetParameter()->Reset();
14531 delete data.GetParameter();
14535 TEST(WeakCallbackApi) {
14536 LocalContext context;
14537 v8::Isolate* isolate = context->GetIsolate();
14538 i::GlobalHandles* globals =
14539 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14540 int initial_handles = globals->global_handles_count();
14542 v8::HandleScope scope(isolate);
14543 v8::Local<v8::Object> obj = v8::Object::New(isolate);
14544 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
14545 v8::Persistent<v8::Object>* handle =
14546 new v8::Persistent<v8::Object>(isolate, obj);
14547 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
14550 reinterpret_cast<i::Isolate*>(isolate)->heap()->
14551 CollectAllGarbage(i::Heap::kNoGCFlags);
14552 // Verify disposed.
14553 CHECK_EQ(initial_handles, globals->global_handles_count());
14557 v8::Persistent<v8::Object> some_object;
14558 v8::Persistent<v8::Object> bad_handle;
14560 void NewPersistentHandleCallback(
14561 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14562 v8::HandleScope scope(data.GetIsolate());
14563 bad_handle.Reset(data.GetIsolate(), some_object);
14564 data.GetParameter()->Reset();
14568 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
14569 LocalContext context;
14570 v8::Isolate* isolate = context->GetIsolate();
14572 v8::Persistent<v8::Object> handle1, handle2;
14574 v8::HandleScope scope(isolate);
14575 some_object.Reset(isolate, v8::Object::New(isolate));
14576 handle1.Reset(isolate, v8::Object::New(isolate));
14577 handle2.Reset(isolate, v8::Object::New(isolate));
14579 // Note: order is implementation dependent alas: currently
14580 // global handle nodes are processed by PostGarbageCollectionProcessing
14581 // in reverse allocation order, so if second allocated handle is deleted,
14582 // weak callback of the first handle would be able to 'reallocate' it.
14583 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
14585 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14589 v8::Persistent<v8::Object> to_be_disposed;
14591 void DisposeAndForceGcCallback(
14592 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14593 to_be_disposed.Reset();
14594 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14595 data.GetParameter()->Reset();
14599 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
14600 LocalContext context;
14601 v8::Isolate* isolate = context->GetIsolate();
14603 v8::Persistent<v8::Object> handle1, handle2;
14605 v8::HandleScope scope(isolate);
14606 handle1.Reset(isolate, v8::Object::New(isolate));
14607 handle2.Reset(isolate, v8::Object::New(isolate));
14609 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
14610 to_be_disposed.Reset(isolate, handle2);
14611 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14614 void DisposingCallback(
14615 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14616 data.GetParameter()->Reset();
14619 void HandleCreatingCallback(
14620 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14621 v8::HandleScope scope(data.GetIsolate());
14622 v8::Persistent<v8::Object>(data.GetIsolate(),
14623 v8::Object::New(data.GetIsolate()));
14624 data.GetParameter()->Reset();
14628 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
14629 LocalContext context;
14630 v8::Isolate* isolate = context->GetIsolate();
14632 v8::Persistent<v8::Object> handle1, handle2, handle3;
14634 v8::HandleScope scope(isolate);
14635 handle3.Reset(isolate, v8::Object::New(isolate));
14636 handle2.Reset(isolate, v8::Object::New(isolate));
14637 handle1.Reset(isolate, v8::Object::New(isolate));
14639 handle2.SetWeak(&handle2, DisposingCallback);
14640 handle3.SetWeak(&handle3, HandleCreatingCallback);
14641 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14645 THREADED_TEST(CheckForCrossContextObjectLiterals) {
14646 v8::V8::Initialize();
14649 const char* sources[nof] = {
14650 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
14654 for (int i = 0; i < nof; i++) {
14655 const char* source = sources[i];
14656 { v8::HandleScope scope(CcTest::isolate());
14657 LocalContext context;
14658 CompileRun(source);
14660 { v8::HandleScope scope(CcTest::isolate());
14661 LocalContext context;
14662 CompileRun(source);
14668 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
14669 v8::EscapableHandleScope inner(env->GetIsolate());
14671 v8::Local<Value> three = v8_num(3);
14672 v8::Local<Value> value = inner.Escape(three);
14678 THREADED_TEST(NestedHandleScopeAndContexts) {
14679 v8::Isolate* isolate = CcTest::isolate();
14680 v8::HandleScope outer(isolate);
14681 v8::Local<Context> env = Context::New(isolate);
14683 v8::Handle<Value> value = NestedScope(env);
14684 v8::Handle<String> str(value->ToString(isolate));
14685 CHECK(!str.IsEmpty());
14690 static bool MatchPointers(void* key1, void* key2) {
14691 return key1 == key2;
14695 struct SymbolInfo {
14702 class SetFunctionEntryHookTest {
14704 SetFunctionEntryHookTest() {
14705 CHECK(instance_ == NULL);
14708 ~SetFunctionEntryHookTest() {
14709 CHECK(instance_ == this);
14714 symbol_locations_.clear();
14715 invocations_.clear();
14718 void OnJitEvent(const v8::JitCodeEvent* event);
14719 static void JitEvent(const v8::JitCodeEvent* event) {
14720 CHECK(instance_ != NULL);
14721 instance_->OnJitEvent(event);
14724 void OnEntryHook(uintptr_t function,
14725 uintptr_t return_addr_location);
14726 static void EntryHook(uintptr_t function,
14727 uintptr_t return_addr_location) {
14728 CHECK(instance_ != NULL);
14729 instance_->OnEntryHook(function, return_addr_location);
14732 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
14733 CHECK(instance_ != NULL);
14734 args.GetReturnValue().Set(v8_num(42));
14736 void RunLoopInNewEnv(v8::Isolate* isolate);
14738 // Records addr as location of symbol.
14739 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
14741 // Finds the symbol containing addr
14742 SymbolInfo* FindSymbolForAddr(i::Address addr);
14743 // Returns the number of invocations where the caller name contains
14744 // \p caller_name and the function name contains \p function_name.
14745 int CountInvocations(const char* caller_name,
14746 const char* function_name);
14748 i::Handle<i::JSFunction> foo_func_;
14749 i::Handle<i::JSFunction> bar_func_;
14751 typedef std::map<size_t, SymbolInfo> SymbolMap;
14752 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
14753 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
14754 SymbolMap symbols_;
14755 SymbolLocationMap symbol_locations_;
14756 InvocationMap invocations_;
14758 static SetFunctionEntryHookTest* instance_;
14760 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
14763 // Returns true if addr is in the range [start, start+len).
14764 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
14765 if (start <= addr && start + len > addr)
14771 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
14772 SymbolInfo* symbol) {
14773 // Insert the symbol at the new location.
14774 SymbolLocationMap::iterator it =
14775 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
14776 // Now erase symbols to the left and right that overlap this one.
14777 while (it != symbol_locations_.begin()) {
14778 SymbolLocationMap::iterator left = it;
14780 if (!Overlaps(left->first, left->second->size, addr))
14782 symbol_locations_.erase(left);
14785 // Now erase symbols to the left and right that overlap this one.
14787 SymbolLocationMap::iterator right = it;
14789 if (right == symbol_locations_.end())
14791 if (!Overlaps(addr, symbol->size, right->first))
14793 symbol_locations_.erase(right);
14798 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14799 switch (event->type) {
14800 case v8::JitCodeEvent::CODE_ADDED: {
14801 CHECK(event->code_start != NULL);
14802 CHECK_NE(0, static_cast<int>(event->code_len));
14803 CHECK(event->name.str != NULL);
14804 size_t symbol_id = symbols_.size();
14806 // Record the new symbol.
14807 SymbolInfo& info = symbols_[symbol_id];
14808 info.id = symbol_id;
14809 info.size = event->code_len;
14810 info.name.assign(event->name.str, event->name.str + event->name.len);
14812 // And record it's location.
14813 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14817 case v8::JitCodeEvent::CODE_MOVED: {
14818 // We would like to never see code move that we haven't seen before,
14819 // but the code creation event does not happen until the line endings
14820 // have been calculated (this is so that we can report the line in the
14821 // script at which the function source is found, see
14822 // Compiler::RecordFunctionCompilation) and the line endings
14823 // calculations can cause a GC, which can move the newly created code
14824 // before its existence can be logged.
14825 SymbolLocationMap::iterator it(
14826 symbol_locations_.find(
14827 reinterpret_cast<i::Address>(event->code_start)));
14828 if (it != symbol_locations_.end()) {
14829 // Found a symbol at this location, move it.
14830 SymbolInfo* info = it->second;
14831 symbol_locations_.erase(it);
14832 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14841 void SetFunctionEntryHookTest::OnEntryHook(
14842 uintptr_t function, uintptr_t return_addr_location) {
14843 // Get the function's code object.
14844 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14845 reinterpret_cast<i::Address>(function));
14846 CHECK(function_code != NULL);
14848 // Then try and look up the caller's code object.
14849 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14851 // Count the invocation.
14852 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14853 SymbolInfo* function_symbol =
14854 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14855 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14857 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14858 // Check that we have a symbol for the "bar" function at the right location.
14859 SymbolLocationMap::iterator it(
14860 symbol_locations_.find(function_code->instruction_start()));
14861 CHECK(it != symbol_locations_.end());
14864 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14865 // Check that we have a symbol for "foo" at the right location.
14866 SymbolLocationMap::iterator it(
14867 symbol_locations_.find(function_code->instruction_start()));
14868 CHECK(it != symbol_locations_.end());
14873 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14874 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14875 // Do we have a direct hit on a symbol?
14876 if (it != symbol_locations_.end()) {
14877 if (it->first == addr)
14881 // If not a direct hit, it'll have to be the previous symbol.
14882 if (it == symbol_locations_.begin())
14886 size_t offs = addr - it->first;
14887 if (offs < it->second->size)
14894 int SetFunctionEntryHookTest::CountInvocations(
14895 const char* caller_name, const char* function_name) {
14896 InvocationMap::iterator it(invocations_.begin());
14897 int invocations = 0;
14898 for (; it != invocations_.end(); ++it) {
14899 SymbolInfo* caller = it->first.first;
14900 SymbolInfo* function = it->first.second;
14902 // Filter out non-matching functions.
14903 if (function_name != NULL) {
14904 if (function->name.find(function_name) == std::string::npos)
14908 // Filter out non-matching callers.
14909 if (caller_name != NULL) {
14910 if (caller == NULL)
14912 if (caller->name.find(caller_name) == std::string::npos)
14916 // It matches add the invocation count to the tally.
14917 invocations += it->second;
14920 return invocations;
14924 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14925 v8::HandleScope outer(isolate);
14926 v8::Local<Context> env = Context::New(isolate);
14929 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14930 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14931 env->Global()->Set(v8_str("obj"), t->NewInstance());
14933 const char* script =
14934 "function bar() {\n"
14936 " for (i = 0; i < 100; ++i)\n"
14940 "function foo(i) { return i * i; }\n"
14941 "// Invoke on the runtime function.\n"
14943 CompileRun(script);
14944 bar_func_ = i::Handle<i::JSFunction>::cast(
14945 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14946 DCHECK(!bar_func_.is_null());
14949 i::Handle<i::JSFunction>::cast(
14950 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14951 DCHECK(!foo_func_.is_null());
14953 v8::Handle<v8::Value> value = CompileRun("bar();");
14954 CHECK(value->IsNumber());
14955 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14957 // Test the optimized codegen path.
14958 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14960 CHECK(value->IsNumber());
14961 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14967 void SetFunctionEntryHookTest::RunTest() {
14968 // Work in a new isolate throughout.
14969 v8::Isolate::CreateParams create_params;
14970 create_params.entry_hook = EntryHook;
14971 create_params.code_event_handler = JitEvent;
14972 v8::Isolate* isolate = v8::Isolate::New(create_params);
14975 v8::Isolate::Scope scope(isolate);
14977 RunLoopInNewEnv(isolate);
14979 // Check the exepected invocation counts.
14980 CHECK_EQ(2, CountInvocations(NULL, "bar"));
14981 CHECK_EQ(200, CountInvocations("bar", "foo"));
14982 CHECK_EQ(200, CountInvocations(NULL, "foo"));
14984 // Verify that we have an entry hook on some specific stubs.
14985 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14986 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14987 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14989 isolate->Dispose();
14993 // Make sure a second isolate is unaffected by the previous entry hook.
14994 isolate = v8::Isolate::New();
14996 v8::Isolate::Scope scope(isolate);
14998 // Reset the entry count to zero and set the entry hook.
14999 RunLoopInNewEnv(isolate);
15001 // We should record no invocations in this isolate.
15002 CHECK_EQ(0, static_cast<int>(invocations_.size()));
15005 isolate->Dispose();
15009 TEST(SetFunctionEntryHook) {
15010 // FunctionEntryHook does not work well with experimental natives.
15011 // Experimental natives are compiled during snapshot deserialization.
15012 // This test breaks because InstallGetter (function from snapshot that
15013 // only gets called from experimental natives) is compiled with entry hooks.
15014 i::FLAG_allow_natives_syntax = true;
15015 i::FLAG_use_inlining = false;
15017 SetFunctionEntryHookTest test;
15022 static i::HashMap* code_map = NULL;
15023 static i::HashMap* jitcode_line_info = NULL;
15024 static int saw_bar = 0;
15025 static int move_events = 0;
15028 static bool FunctionNameIs(const char* expected,
15029 const v8::JitCodeEvent* event) {
15030 // Log lines for functions are of the general form:
15031 // "LazyCompile:<type><function_name>", where the type is one of
15033 static const char kPreamble[] = "LazyCompile:";
15034 static size_t kPreambleLen = sizeof(kPreamble) - 1;
15036 if (event->name.len < sizeof(kPreamble) - 1 ||
15037 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
15041 const char* tail = event->name.str + kPreambleLen;
15042 size_t tail_len = event->name.len - kPreambleLen;
15043 size_t expected_len = strlen(expected);
15044 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
15049 // Check for tails like 'bar :1'.
15050 if (tail_len > expected_len + 2 &&
15051 tail[expected_len] == ' ' &&
15052 tail[expected_len + 1] == ':' &&
15053 tail[expected_len + 2] &&
15054 !strncmp(tail, expected, expected_len)) {
15058 if (tail_len != expected_len)
15061 return strncmp(tail, expected, expected_len) == 0;
15065 static void event_handler(const v8::JitCodeEvent* event) {
15066 CHECK(event != NULL);
15067 CHECK(code_map != NULL);
15068 CHECK(jitcode_line_info != NULL);
15070 class DummyJitCodeLineInfo {
15073 switch (event->type) {
15074 case v8::JitCodeEvent::CODE_ADDED: {
15075 CHECK(event->code_start != NULL);
15076 CHECK_NE(0, static_cast<int>(event->code_len));
15077 CHECK(event->name.str != NULL);
15078 i::HashMap::Entry* entry =
15079 code_map->Lookup(event->code_start,
15080 i::ComputePointerHash(event->code_start),
15082 entry->value = reinterpret_cast<void*>(event->code_len);
15084 if (FunctionNameIs("bar", event)) {
15090 case v8::JitCodeEvent::CODE_MOVED: {
15091 uint32_t hash = i::ComputePointerHash(event->code_start);
15092 // We would like to never see code move that we haven't seen before,
15093 // but the code creation event does not happen until the line endings
15094 // have been calculated (this is so that we can report the line in the
15095 // script at which the function source is found, see
15096 // Compiler::RecordFunctionCompilation) and the line endings
15097 // calculations can cause a GC, which can move the newly created code
15098 // before its existence can be logged.
15099 i::HashMap::Entry* entry =
15100 code_map->Lookup(event->code_start, hash, false);
15101 if (entry != NULL) {
15104 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
15105 code_map->Remove(event->code_start, hash);
15107 entry = code_map->Lookup(event->new_code_start,
15108 i::ComputePointerHash(event->new_code_start),
15110 CHECK(entry != NULL);
15111 entry->value = reinterpret_cast<void*>(event->code_len);
15116 case v8::JitCodeEvent::CODE_REMOVED:
15117 // Object/code removal events are currently not dispatched from the GC.
15121 // For CODE_START_LINE_INFO_RECORDING event, we will create one
15122 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
15123 // record it in jitcode_line_info.
15124 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
15125 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
15126 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
15127 temp_event->user_data = line_info;
15128 i::HashMap::Entry* entry =
15129 jitcode_line_info->Lookup(line_info,
15130 i::ComputePointerHash(line_info),
15132 entry->value = reinterpret_cast<void*>(line_info);
15135 // For these two events, we will check whether the event->user_data
15136 // data structure is created before during CODE_START_LINE_INFO_RECORDING
15137 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
15138 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
15139 CHECK(event->user_data != NULL);
15140 uint32_t hash = i::ComputePointerHash(event->user_data);
15141 i::HashMap::Entry* entry =
15142 jitcode_line_info->Lookup(event->user_data, hash, false);
15143 CHECK(entry != NULL);
15144 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
15148 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
15149 CHECK(event->user_data != NULL);
15150 uint32_t hash = i::ComputePointerHash(event->user_data);
15151 i::HashMap::Entry* entry =
15152 jitcode_line_info->Lookup(event->user_data, hash, false);
15153 CHECK(entry != NULL);
15158 // Impossible event.
15165 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
15166 i::FLAG_stress_compaction = true;
15167 i::FLAG_incremental_marking = false;
15168 if (i::FLAG_never_compact) return;
15169 const char* script =
15172 " for (i = 0; i < 100; ++i)"
15176 "function foo(i) { return i * i; };"
15179 // Run this test in a new isolate to make sure we don't
15180 // have remnants of state from other code.
15181 v8::Isolate* isolate = v8::Isolate::New();
15183 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
15184 i::Heap* heap = i_isolate->heap();
15187 v8::HandleScope scope(isolate);
15188 i::HashMap code(MatchPointers);
15191 i::HashMap lineinfo(MatchPointers);
15192 jitcode_line_info = &lineinfo;
15197 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
15199 // Generate new code objects sparsely distributed across several
15200 // different fragmented code-space pages.
15201 const int kIterations = 10;
15202 for (int i = 0; i < kIterations; ++i) {
15203 LocalContext env(isolate);
15204 i::AlwaysAllocateScope always_allocate(i_isolate);
15205 SimulateFullSpace(heap->code_space());
15206 CompileRun(script);
15208 // Keep a strong reference to the code object in the handle scope.
15209 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
15210 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
15211 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
15212 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
15214 // Clear the compilation cache to get more wastage.
15215 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
15218 // Force code movement.
15219 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
15221 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
15223 CHECK_LE(kIterations, saw_bar);
15224 CHECK_LT(0, move_events);
15227 jitcode_line_info = NULL;
15231 isolate->Dispose();
15233 // Do this in a new isolate.
15234 isolate = v8::Isolate::New();
15237 // Verify that we get callbacks for existing code objects when we
15238 // request enumeration of existing code.
15240 v8::HandleScope scope(isolate);
15241 LocalContext env(isolate);
15242 CompileRun(script);
15244 // Now get code through initial iteration.
15245 i::HashMap code(MatchPointers);
15248 i::HashMap lineinfo(MatchPointers);
15249 jitcode_line_info = &lineinfo;
15251 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
15253 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
15255 jitcode_line_info = NULL;
15256 // We expect that we got some events. Note that if we could get code removal
15257 // notifications, we could compare two collections, one created by listening
15258 // from the time of creation of an isolate, and the other by subscribing
15259 // with EnumExisting.
15260 CHECK_LT(0, code.occupancy());
15266 isolate->Dispose();
15270 THREADED_TEST(ExternalAllocatedMemory) {
15271 v8::Isolate* isolate = CcTest::isolate();
15272 v8::HandleScope outer(isolate);
15273 v8::Local<Context> env(Context::New(isolate));
15274 CHECK(!env.IsEmpty());
15275 const int64_t kSize = 1024*1024;
15276 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
15277 CHECK_EQ(baseline + kSize,
15278 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
15280 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
15284 // Regression test for issue 54, object templates with internal fields
15285 // but no accessors or interceptors did not get their internal field
15286 // count set on instances.
15287 THREADED_TEST(Regress54) {
15288 LocalContext context;
15289 v8::Isolate* isolate = context->GetIsolate();
15290 v8::HandleScope outer(isolate);
15291 static v8::Persistent<v8::ObjectTemplate> templ;
15292 if (templ.IsEmpty()) {
15293 v8::EscapableHandleScope inner(isolate);
15294 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
15295 local->SetInternalFieldCount(1);
15296 templ.Reset(isolate, inner.Escape(local));
15298 v8::Handle<v8::Object> result =
15299 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
15300 CHECK_EQ(1, result->InternalFieldCount());
15304 // If part of the threaded tests, this test makes ThreadingTest fail
15306 TEST(CatchStackOverflow) {
15307 LocalContext context;
15308 v8::HandleScope scope(context->GetIsolate());
15309 v8::TryCatch try_catch;
15310 v8::Handle<v8::Value> result = CompileRun(
15316 CHECK(result.IsEmpty());
15320 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
15321 const char* resource_name,
15323 v8::HandleScope scope(CcTest::isolate());
15324 v8::TryCatch try_catch;
15325 v8::Handle<v8::Value> result = script->Run();
15326 CHECK(result.IsEmpty());
15327 CHECK(try_catch.HasCaught());
15328 v8::Handle<v8::Message> message = try_catch.Message();
15329 CHECK(!message.IsEmpty());
15330 CHECK_EQ(10 + line_offset, message->GetLineNumber());
15331 CHECK_EQ(91, message->GetStartPosition());
15332 CHECK_EQ(92, message->GetEndPosition());
15333 CHECK_EQ(2, message->GetStartColumn());
15334 CHECK_EQ(3, message->GetEndColumn());
15335 v8::String::Utf8Value line(message->GetSourceLine());
15336 CHECK_EQ(" throw 'nirk';", *line);
15337 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
15338 CHECK_EQ(resource_name, *name);
15342 THREADED_TEST(TryCatchSourceInfo) {
15343 LocalContext context;
15344 v8::HandleScope scope(context->GetIsolate());
15345 v8::Local<v8::String> source = v8_str(
15346 "function Foo() {\n"
15350 "function Bar() {\n"
15354 "function Baz() {\n"
15360 const char* resource_name;
15361 v8::Handle<v8::Script> script;
15362 resource_name = "test.js";
15363 script = CompileWithOrigin(source, resource_name);
15364 CheckTryCatchSourceInfo(script, resource_name, 0);
15366 resource_name = "test1.js";
15367 v8::ScriptOrigin origin1(
15368 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
15369 script = v8::Script::Compile(source, &origin1);
15370 CheckTryCatchSourceInfo(script, resource_name, 0);
15372 resource_name = "test2.js";
15373 v8::ScriptOrigin origin2(
15374 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
15375 v8::Integer::New(context->GetIsolate(), 7));
15376 script = v8::Script::Compile(source, &origin2);
15377 CheckTryCatchSourceInfo(script, resource_name, 7);
15381 THREADED_TEST(CompilationCache) {
15382 LocalContext context;
15383 v8::HandleScope scope(context->GetIsolate());
15384 v8::Handle<v8::String> source0 =
15385 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
15386 v8::Handle<v8::String> source1 =
15387 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
15388 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
15389 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
15390 v8::Handle<v8::Script> script2 =
15391 v8::Script::Compile(source0); // different origin
15392 CHECK_EQ(1234, script0->Run()->Int32Value());
15393 CHECK_EQ(1234, script1->Run()->Int32Value());
15394 CHECK_EQ(1234, script2->Run()->Int32Value());
15398 static void FunctionNameCallback(
15399 const v8::FunctionCallbackInfo<v8::Value>& args) {
15400 ApiTestFuzzer::Fuzz();
15401 args.GetReturnValue().Set(v8_num(42));
15405 THREADED_TEST(CallbackFunctionName) {
15406 LocalContext context;
15407 v8::Isolate* isolate = context->GetIsolate();
15408 v8::HandleScope scope(isolate);
15409 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
15410 t->Set(v8_str("asdf"),
15411 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
15412 context->Global()->Set(v8_str("obj"), t->NewInstance());
15413 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
15414 CHECK(value->IsString());
15415 v8::String::Utf8Value name(value);
15416 CHECK_EQ("asdf", *name);
15420 THREADED_TEST(DateAccess) {
15421 LocalContext context;
15422 v8::HandleScope scope(context->GetIsolate());
15423 v8::Handle<v8::Value> date =
15424 v8::Date::New(context->GetIsolate(), 1224744689038.0);
15425 CHECK(date->IsDate());
15426 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
15430 void CheckProperties(v8::Isolate* isolate,
15431 v8::Handle<v8::Value> val,
15433 const char* elmv[]) {
15434 v8::Handle<v8::Object> obj = val.As<v8::Object>();
15435 v8::Handle<v8::Array> props = obj->GetPropertyNames();
15436 CHECK_EQ(elmc, props->Length());
15437 for (int i = 0; i < elmc; i++) {
15438 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
15439 CHECK_EQ(elmv[i], *elm);
15444 void CheckOwnProperties(v8::Isolate* isolate,
15445 v8::Handle<v8::Value> val,
15447 const char* elmv[]) {
15448 v8::Handle<v8::Object> obj = val.As<v8::Object>();
15449 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
15450 CHECK_EQ(elmc, props->Length());
15451 for (int i = 0; i < elmc; i++) {
15452 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
15453 CHECK_EQ(elmv[i], *elm);
15458 THREADED_TEST(PropertyEnumeration) {
15459 LocalContext context;
15460 v8::Isolate* isolate = context->GetIsolate();
15461 v8::HandleScope scope(isolate);
15462 v8::Handle<v8::Value> obj = CompileRun(
15465 "result[1] = {a: 1, b: 2};"
15466 "result[2] = [1, 2, 3];"
15467 "var proto = {x: 1, y: 2, z: 3};"
15468 "var x = { __proto__: proto, w: 0, z: 1 };"
15471 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
15472 CHECK_EQ(4, elms->Length());
15474 const char** elmv0 = NULL;
15476 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15477 CheckOwnProperties(
15478 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15480 const char* elmv1[] = {"a", "b"};
15482 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
15483 CheckOwnProperties(
15484 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
15486 const char* elmv2[] = {"0", "1", "2"};
15488 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
15489 CheckOwnProperties(
15490 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
15492 const char* elmv3[] = {"w", "z", "x", "y"};
15494 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
15496 const char* elmv4[] = {"w", "z"};
15497 CheckOwnProperties(
15498 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
15502 THREADED_TEST(PropertyEnumeration2) {
15503 LocalContext context;
15504 v8::Isolate* isolate = context->GetIsolate();
15505 v8::HandleScope scope(isolate);
15506 v8::Handle<v8::Value> obj = CompileRun(
15509 "result[1] = {a: 1, b: 2};"
15510 "result[2] = [1, 2, 3];"
15511 "var proto = {x: 1, y: 2, z: 3};"
15512 "var x = { __proto__: proto, w: 0, z: 1 };"
15515 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
15516 CHECK_EQ(4, elms->Length());
15518 const char** elmv0 = NULL;
15519 CheckProperties(isolate,
15520 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15522 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
15523 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
15524 CHECK_EQ(0, props->Length());
15525 for (uint32_t i = 0; i < props->Length(); i++) {
15526 printf("p[%u]\n", i);
15530 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
15532 v8::AccessType type,
15533 Local<Value> data) {
15534 return type != v8::ACCESS_SET;
15538 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
15540 v8::AccessType type,
15541 Local<Value> data) {
15542 return type != v8::ACCESS_SET;
15546 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
15547 LocalContext context;
15548 v8::Isolate* isolate = context->GetIsolate();
15549 v8::HandleScope scope(isolate);
15550 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15551 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
15552 IndexedSetAccessBlocker);
15553 templ->Set(v8_str("x"), v8::True(isolate));
15554 Local<v8::Object> instance = templ->NewInstance();
15555 context->Global()->Set(v8_str("obj"), instance);
15556 Local<Value> value = CompileRun("obj.x");
15557 CHECK(value->BooleanValue());
15561 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
15563 v8::AccessType type,
15564 Local<Value> data) {
15569 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
15571 v8::AccessType type,
15572 Local<Value> data) {
15578 THREADED_TEST(AccessChecksReenabledCorrectly) {
15579 LocalContext context;
15580 v8::Isolate* isolate = context->GetIsolate();
15581 v8::HandleScope scope(isolate);
15582 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15583 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15584 IndexedGetAccessBlocker);
15585 templ->Set(v8_str("a"), v8_str("a"));
15586 // Add more than 8 (see kMaxFastProperties) properties
15587 // so that the constructor will force copying map.
15588 // Cannot sprintf, gcc complains unsafety.
15590 for (char i = '0'; i <= '9' ; i++) {
15592 for (char j = '0'; j <= '9'; j++) {
15594 for (char k = '0'; k <= '9'; k++) {
15597 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
15602 Local<v8::Object> instance_1 = templ->NewInstance();
15603 context->Global()->Set(v8_str("obj_1"), instance_1);
15605 Local<Value> value_1 = CompileRun("obj_1.a");
15606 CHECK(value_1.IsEmpty());
15608 Local<v8::Object> instance_2 = templ->NewInstance();
15609 context->Global()->Set(v8_str("obj_2"), instance_2);
15611 Local<Value> value_2 = CompileRun("obj_2.a");
15612 CHECK(value_2.IsEmpty());
15616 // This tests that access check information remains on the global
15617 // object template when creating contexts.
15618 THREADED_TEST(AccessControlRepeatedContextCreation) {
15619 v8::Isolate* isolate = CcTest::isolate();
15620 v8::HandleScope handle_scope(isolate);
15621 v8::Handle<v8::ObjectTemplate> global_template =
15622 v8::ObjectTemplate::New(isolate);
15623 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
15624 IndexedSetAccessBlocker);
15625 i::Handle<i::ObjectTemplateInfo> internal_template =
15626 v8::Utils::OpenHandle(*global_template);
15627 CHECK(!internal_template->constructor()->IsUndefined());
15628 i::Handle<i::FunctionTemplateInfo> constructor(
15629 i::FunctionTemplateInfo::cast(internal_template->constructor()));
15630 CHECK(!constructor->access_check_info()->IsUndefined());
15631 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
15632 CHECK(!context0.IsEmpty());
15633 CHECK(!constructor->access_check_info()->IsUndefined());
15637 THREADED_TEST(TurnOnAccessCheck) {
15638 v8::Isolate* isolate = CcTest::isolate();
15639 v8::HandleScope handle_scope(isolate);
15641 // Create an environment with access check to the global object disabled by
15643 v8::Handle<v8::ObjectTemplate> global_template =
15644 v8::ObjectTemplate::New(isolate);
15645 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15646 IndexedGetAccessBlocker,
15647 v8::Handle<v8::Value>(),
15649 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
15650 Context::Scope context_scope(context);
15652 // Set up a property and a number of functions.
15653 context->Global()->Set(v8_str("a"), v8_num(1));
15654 CompileRun("function f1() {return a;}"
15655 "function f2() {return a;}"
15656 "function g1() {return h();}"
15657 "function g2() {return h();}"
15658 "function h() {return 1;}");
15659 Local<Function> f1 =
15660 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15661 Local<Function> f2 =
15662 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15663 Local<Function> g1 =
15664 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15665 Local<Function> g2 =
15666 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15667 Local<Function> h =
15668 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15670 // Get the global object.
15671 v8::Handle<v8::Object> global = context->Global();
15673 // Call f1 one time and f2 a number of times. This will ensure that f1 still
15674 // uses the runtime system to retreive property a whereas f2 uses global load
15676 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15677 for (int i = 0; i < 4; i++) {
15678 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15681 // Same for g1 and g2.
15682 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15683 for (int i = 0; i < 4; i++) {
15684 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15687 // Detach the global and turn on access check.
15688 Local<Object> hidden_global = Local<Object>::Cast(
15689 context->Global()->GetPrototype());
15690 context->DetachGlobal();
15691 hidden_global->TurnOnAccessCheck();
15693 // Failing access check results in exception.
15694 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15695 CHECK(f2->Call(global, 0, NULL).IsEmpty());
15696 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15697 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15699 // No failing access check when just returning a constant.
15700 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15704 static const char* kPropertyA = "a";
15705 static const char* kPropertyH = "h";
15707 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
15709 v8::AccessType type,
15710 Local<Value> data) {
15711 if (!name->IsString()) return false;
15712 i::Handle<i::String> name_handle =
15713 v8::Utils::OpenHandle(String::Cast(*name));
15714 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
15715 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
15719 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
15720 v8::Isolate* isolate = CcTest::isolate();
15721 v8::HandleScope handle_scope(isolate);
15723 // Create an environment with access check to the global object disabled by
15724 // default. When the registered access checker will block access to properties
15726 v8::Handle<v8::ObjectTemplate> global_template =
15727 v8::ObjectTemplate::New(isolate);
15728 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
15729 IndexedGetAccessBlocker,
15730 v8::Handle<v8::Value>(),
15732 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
15733 Context::Scope context_scope(context);
15735 // Set up a property and a number of functions.
15736 context->Global()->Set(v8_str("a"), v8_num(1));
15737 static const char* source = "function f1() {return a;}"
15738 "function f2() {return a;}"
15739 "function g1() {return h();}"
15740 "function g2() {return h();}"
15741 "function h() {return 1;}";
15743 CompileRun(source);
15744 Local<Function> f1;
15745 Local<Function> f2;
15746 Local<Function> g1;
15747 Local<Function> g2;
15749 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15750 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15751 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15752 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15753 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15755 // Get the global object.
15756 v8::Handle<v8::Object> global = context->Global();
15758 // Call f1 one time and f2 a number of times. This will ensure that f1 still
15759 // uses the runtime system to retreive property a whereas f2 uses global load
15761 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15762 for (int i = 0; i < 4; i++) {
15763 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15766 // Same for g1 and g2.
15767 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15768 for (int i = 0; i < 4; i++) {
15769 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15772 // Detach the global and turn on access check now blocking access to property
15773 // a and function h.
15774 Local<Object> hidden_global = Local<Object>::Cast(
15775 context->Global()->GetPrototype());
15776 context->DetachGlobal();
15777 hidden_global->TurnOnAccessCheck();
15779 // Failing access check results in exception.
15780 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15781 CHECK(f2->Call(global, 0, NULL).IsEmpty());
15782 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15783 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15785 // No failing access check when just returning a constant.
15786 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15788 // Now compile the source again. And get the newly compiled functions, except
15789 // for h for which access is blocked.
15790 CompileRun(source);
15791 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
15792 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
15793 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
15794 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
15795 CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
15797 // Failing access check results in exception.
15798 v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
15799 CHECK(result.IsEmpty());
15800 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15801 CHECK(f2->Call(global, 0, NULL).IsEmpty());
15802 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15803 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15807 // Tests that ScriptData can be serialized and deserialized.
15808 TEST(PreCompileSerialization) {
15809 v8::V8::Initialize();
15811 v8::Isolate* isolate = env->GetIsolate();
15812 HandleScope handle_scope(isolate);
15814 i::FLAG_min_preparse_length = 0;
15815 const char* script = "function foo(a) { return a+1; }";
15816 v8::ScriptCompiler::Source source(v8_str(script));
15817 v8::ScriptCompiler::Compile(isolate, &source,
15818 v8::ScriptCompiler::kProduceParserCache);
15820 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15821 i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15822 i::MemCopy(serialized_data, cd->data, cd->length);
15825 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
15827 // Verify that the original is the same as the deserialized.
15828 CHECK_EQ(cd->length, deserialized->length());
15829 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
15831 delete deserialized;
15832 i::DeleteArray(serialized_data);
15836 // This tests that we do not allow dictionary load/call inline caches
15837 // to use functions that have not yet been compiled. The potential
15838 // problem of loading a function that has not yet been compiled can
15839 // arise because we share code between contexts via the compilation
15841 THREADED_TEST(DictionaryICLoadedFunction) {
15842 v8::HandleScope scope(CcTest::isolate());
15844 for (int i = 0; i < 2; i++) {
15845 LocalContext context;
15846 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15847 context->Global()->Delete(v8_str("tmp"));
15848 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15851 for (int i = 0; i < 2; i++) {
15852 LocalContext context;
15853 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15854 context->Global()->Delete(v8_str("tmp"));
15855 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15860 // Test that cross-context new calls use the context of the callee to
15861 // create the new JavaScript object.
15862 THREADED_TEST(CrossContextNew) {
15863 v8::Isolate* isolate = CcTest::isolate();
15864 v8::HandleScope scope(isolate);
15865 v8::Local<Context> context0 = Context::New(isolate);
15866 v8::Local<Context> context1 = Context::New(isolate);
15868 // Allow cross-domain access.
15869 Local<String> token = v8_str("<security token>");
15870 context0->SetSecurityToken(token);
15871 context1->SetSecurityToken(token);
15873 // Set an 'x' property on the Object prototype and define a
15874 // constructor function in context0.
15876 CompileRun("Object.prototype.x = 42; function C() {};");
15879 // Call the constructor function from context0 and check that the
15880 // result has the 'x' property.
15882 context1->Global()->Set(v8_str("other"), context0->Global());
15883 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15884 CHECK(value->IsInt32());
15885 CHECK_EQ(42, value->Int32Value());
15890 // Verify that we can clone an object
15891 TEST(ObjectClone) {
15893 v8::Isolate* isolate = env->GetIsolate();
15894 v8::HandleScope scope(isolate);
15896 const char* sample =
15898 "rv.alpha = 'hello';" \
15902 // Create an object, verify basics.
15903 Local<Value> val = CompileRun(sample);
15904 CHECK(val->IsObject());
15905 Local<v8::Object> obj = val.As<v8::Object>();
15906 obj->Set(v8_str("gamma"), v8_str("cloneme"));
15908 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15909 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15910 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15913 Local<v8::Object> clone = obj->Clone();
15914 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15915 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15916 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15918 // Set a property on the clone, verify each object.
15919 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15920 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15921 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15925 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15927 explicit OneByteVectorResource(i::Vector<const char> vector)
15929 virtual ~OneByteVectorResource() {}
15930 virtual size_t length() const { return data_.length(); }
15931 virtual const char* data() const { return data_.start(); }
15933 i::Vector<const char> data_;
15937 class UC16VectorResource : public v8::String::ExternalStringResource {
15939 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15941 virtual ~UC16VectorResource() {}
15942 virtual size_t length() const { return data_.length(); }
15943 virtual const i::uc16* data() const { return data_.start(); }
15945 i::Vector<const i::uc16> data_;
15949 static void MorphAString(i::String* string,
15950 OneByteVectorResource* one_byte_resource,
15951 UC16VectorResource* uc16_resource) {
15952 CHECK(i::StringShape(string).IsExternal());
15953 if (string->IsOneByteRepresentation()) {
15954 // Check old map is not internalized or long.
15955 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
15956 // Morph external string to be TwoByte string.
15957 string->set_map(CcTest::heap()->external_string_map());
15958 i::ExternalTwoByteString* morphed =
15959 i::ExternalTwoByteString::cast(string);
15960 morphed->set_resource(uc16_resource);
15962 // Check old map is not internalized or long.
15963 CHECK(string->map() == CcTest::heap()->external_string_map());
15964 // Morph external string to be one-byte string.
15965 string->set_map(CcTest::heap()->external_one_byte_string_map());
15966 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15967 morphed->set_resource(one_byte_resource);
15972 // Test that we can still flatten a string if the components it is built up
15973 // from have been turned into 16 bit strings in the mean time.
15974 THREADED_TEST(MorphCompositeStringTest) {
15975 char utf_buffer[129];
15976 const char* c_string = "Now is the time for all good men"
15977 " to come to the aid of the party";
15978 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15981 i::Factory* factory = CcTest::i_isolate()->factory();
15982 v8::HandleScope scope(env->GetIsolate());
15983 OneByteVectorResource one_byte_resource(
15984 i::Vector<const char>(c_string, i::StrLength(c_string)));
15985 UC16VectorResource uc16_resource(
15986 i::Vector<const uint16_t>(two_byte_string,
15987 i::StrLength(c_string)));
15990 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15991 &one_byte_resource).ToHandleChecked()));
15993 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15994 &one_byte_resource).ToHandleChecked()));
15996 env->Global()->Set(v8_str("lhs"), lhs);
15997 env->Global()->Set(v8_str("rhs"), rhs);
16000 "var cons = lhs + rhs;"
16001 "var slice = lhs.substring(1, lhs.length - 1);"
16002 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
16004 CHECK(lhs->IsOneByte());
16005 CHECK(rhs->IsOneByte());
16007 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
16009 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
16012 // This should UTF-8 without flattening, since everything is ASCII.
16013 Handle<String> cons = v8_compile("cons")->Run().As<String>();
16014 CHECK_EQ(128, cons->Utf8Length());
16016 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
16017 CHECK_EQ(128, nchars);
16018 CHECK_EQ(0, strcmp(
16020 "Now is the time for all good men to come to the aid of the party"
16021 "Now is the time for all good men to come to the aid of the party"));
16023 // Now do some stuff to make sure the strings are flattened, etc.
16025 "/[^a-z]/.test(cons);"
16026 "/[^a-z]/.test(slice);"
16027 "/[^a-z]/.test(slice_on_cons);");
16028 const char* expected_cons =
16029 "Now is the time for all good men to come to the aid of the party"
16030 "Now is the time for all good men to come to the aid of the party";
16031 const char* expected_slice =
16032 "ow is the time for all good men to come to the aid of the part";
16033 const char* expected_slice_on_cons =
16034 "ow is the time for all good men to come to the aid of the party"
16035 "Now is the time for all good men to come to the aid of the part";
16036 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
16037 env->Global()->Get(v8_str("cons")));
16038 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
16039 env->Global()->Get(v8_str("slice")));
16040 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
16041 env->Global()->Get(v8_str("slice_on_cons")));
16043 i::DeleteArray(two_byte_string);
16047 TEST(CompileExternalTwoByteSource) {
16048 LocalContext context;
16049 v8::HandleScope scope(context->GetIsolate());
16051 // This is a very short list of sources, which currently is to check for a
16052 // regression caused by r2703.
16053 const char* one_byte_sources[] = {
16055 "-0.5", // This mainly testes PushBack in the Scanner.
16056 "--0.5", // This mainly testes PushBack in the Scanner.
16059 // Compile the sources as external two byte strings.
16060 for (int i = 0; one_byte_sources[i] != NULL; i++) {
16061 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
16062 TestResource* uc16_resource = new TestResource(two_byte_string);
16063 v8::Local<v8::String> source =
16064 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
16065 v8::Script::Compile(source);
16070 #ifndef V8_INTERPRETED_REGEXP
16072 struct RegExpInterruptionData {
16073 v8::base::Atomic32 loop_count;
16074 UC16VectorResource* string_resource;
16075 v8::Persistent<v8::String> string;
16076 } regexp_interruption_data;
16079 class RegExpInterruptionThread : public v8::base::Thread {
16081 explicit RegExpInterruptionThread(v8::Isolate* isolate)
16082 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
16084 virtual void Run() {
16085 for (v8::base::NoBarrier_Store(®exp_interruption_data.loop_count, 0);
16086 v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) < 7;
16087 v8::base::NoBarrier_AtomicIncrement(
16088 ®exp_interruption_data.loop_count, 1)) {
16089 v8::base::OS::Sleep(50); // Wait a bit before requesting GC.
16090 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
16092 v8::base::OS::Sleep(50); // Wait a bit before terminating.
16093 v8::V8::TerminateExecution(isolate_);
16097 v8::Isolate* isolate_;
16101 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
16102 if (v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) != 2) {
16105 v8::HandleScope scope(CcTest::isolate());
16106 v8::Local<v8::String> string = v8::Local<v8::String>::New(
16107 CcTest::isolate(), regexp_interruption_data.string);
16108 string->MakeExternal(regexp_interruption_data.string_resource);
16112 // Test that RegExp execution can be interrupted. Specifically, we test
16113 // * interrupting with GC
16114 // * turn the subject string from one-byte internal to two-byte external string
16115 // * force termination
16116 TEST(RegExpInterruption) {
16117 v8::HandleScope scope(CcTest::isolate());
16120 RegExpInterruptionThread timeout_thread(CcTest::isolate());
16122 v8::V8::AddGCPrologueCallback(RunBeforeGC);
16123 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
16124 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
16125 v8::Local<v8::String> string = v8_str(one_byte_content);
16127 CcTest::global()->Set(v8_str("a"), string);
16128 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
16129 regexp_interruption_data.string_resource = new UC16VectorResource(
16130 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
16132 v8::TryCatch try_catch;
16133 timeout_thread.Start();
16135 CompileRun("/((a*)*)*b/.exec(a)");
16136 CHECK(try_catch.HasTerminated());
16138 timeout_thread.Join();
16140 regexp_interruption_data.string.Reset();
16141 i::DeleteArray(uc16_content);
16144 #endif // V8_INTERPRETED_REGEXP
16147 // Test that we cannot set a property on the global object if there
16148 // is a read-only property in the prototype chain.
16149 TEST(ReadOnlyPropertyInGlobalProto) {
16150 v8::Isolate* isolate = CcTest::isolate();
16151 v8::HandleScope scope(isolate);
16152 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16153 LocalContext context(0, templ);
16154 v8::Handle<v8::Object> global = context->Global();
16155 v8::Handle<v8::Object> global_proto =
16156 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
16157 global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
16159 global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
16161 // Check without 'eval' or 'with'.
16162 v8::Handle<v8::Value> res =
16163 CompileRun("function f() { x = 42; return x; }; f()");
16164 CHECK_EQ(v8::Integer::New(isolate, 0), res);
16165 // Check with 'eval'.
16166 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
16167 CHECK_EQ(v8::Integer::New(isolate, 0), res);
16168 // Check with 'with'.
16169 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
16170 CHECK_EQ(v8::Integer::New(isolate, 0), res);
16173 static int force_set_set_count = 0;
16174 static int force_set_get_count = 0;
16175 bool pass_on_get = false;
16177 static void ForceSetGetter(v8::Local<v8::String> name,
16178 const v8::PropertyCallbackInfo<v8::Value>& info) {
16179 force_set_get_count++;
16183 info.GetReturnValue().Set(3);
16186 static void ForceSetSetter(v8::Local<v8::String> name,
16187 v8::Local<v8::Value> value,
16188 const v8::PropertyCallbackInfo<void>& info) {
16189 force_set_set_count++;
16192 static void ForceSetInterceptGetter(
16193 v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
16194 CHECK(name->IsString());
16195 ForceSetGetter(Local<String>::Cast(name), info);
16198 static void ForceSetInterceptSetter(
16199 v8::Local<v8::Name> name, v8::Local<v8::Value> value,
16200 const v8::PropertyCallbackInfo<v8::Value>& info) {
16201 force_set_set_count++;
16202 info.GetReturnValue().SetUndefined();
16207 force_set_get_count = 0;
16208 force_set_set_count = 0;
16209 pass_on_get = false;
16211 v8::Isolate* isolate = CcTest::isolate();
16212 v8::HandleScope scope(isolate);
16213 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16214 v8::Handle<v8::String> access_property =
16215 v8::String::NewFromUtf8(isolate, "a");
16216 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
16217 LocalContext context(NULL, templ);
16218 v8::Handle<v8::Object> global = context->Global();
16220 // Ordinary properties
16221 v8::Handle<v8::String> simple_property =
16222 v8::String::NewFromUtf8(isolate, "p");
16223 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
16224 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16225 // This should fail because the property is read-only
16226 global->Set(simple_property, v8::Int32::New(isolate, 5));
16227 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16228 // This should succeed even though the property is read-only
16229 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
16230 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
16233 CHECK_EQ(0, force_set_set_count);
16234 CHECK_EQ(0, force_set_get_count);
16235 CHECK_EQ(3, global->Get(access_property)->Int32Value());
16236 // CHECK_EQ the property shouldn't override it, just call the setter
16237 // which in this case does nothing.
16238 global->Set(access_property, v8::Int32::New(isolate, 7));
16239 CHECK_EQ(3, global->Get(access_property)->Int32Value());
16240 CHECK_EQ(1, force_set_set_count);
16241 CHECK_EQ(2, force_set_get_count);
16242 // Forcing the property to be set should override the accessor without
16244 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
16245 CHECK_EQ(8, global->Get(access_property)->Int32Value());
16246 CHECK_EQ(1, force_set_set_count);
16247 CHECK_EQ(2, force_set_get_count);
16251 TEST(ForceSetWithInterceptor) {
16252 force_set_get_count = 0;
16253 force_set_set_count = 0;
16254 pass_on_get = false;
16256 v8::Isolate* isolate = CcTest::isolate();
16257 v8::HandleScope scope(isolate);
16258 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16259 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
16260 ForceSetInterceptGetter, ForceSetInterceptSetter));
16261 LocalContext context(NULL, templ);
16262 v8::Handle<v8::Object> global = context->Global();
16264 v8::Handle<v8::String> some_property =
16265 v8::String::NewFromUtf8(isolate, "a");
16266 CHECK_EQ(0, force_set_set_count);
16267 CHECK_EQ(0, force_set_get_count);
16268 CHECK_EQ(3, global->Get(some_property)->Int32Value());
16269 // Setting the property shouldn't override it, just call the setter
16270 // which in this case does nothing.
16271 global->Set(some_property, v8::Int32::New(isolate, 7));
16272 CHECK_EQ(3, global->Get(some_property)->Int32Value());
16273 CHECK_EQ(1, force_set_set_count);
16274 CHECK_EQ(2, force_set_get_count);
16275 // Getting the property when the interceptor returns an empty handle
16276 // should yield undefined, since the property isn't present on the
16277 // object itself yet.
16278 pass_on_get = true;
16279 CHECK(global->Get(some_property)->IsUndefined());
16280 CHECK_EQ(1, force_set_set_count);
16281 CHECK_EQ(3, force_set_get_count);
16282 // Forcing the property to be set should cause the value to be
16283 // set locally without calling the interceptor.
16284 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
16285 CHECK_EQ(8, global->Get(some_property)->Int32Value());
16286 CHECK_EQ(1, force_set_set_count);
16287 CHECK_EQ(4, force_set_get_count);
16288 // Reenabling the interceptor should cause it to take precedence over
16290 pass_on_get = false;
16291 CHECK_EQ(3, global->Get(some_property)->Int32Value());
16292 CHECK_EQ(1, force_set_set_count);
16293 CHECK_EQ(5, force_set_get_count);
16294 // The interceptor should also work for other properties
16295 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
16297 CHECK_EQ(1, force_set_set_count);
16298 CHECK_EQ(6, force_set_get_count);
16302 THREADED_TEST(ForceDelete) {
16303 v8::Isolate* isolate = CcTest::isolate();
16304 v8::HandleScope scope(isolate);
16305 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16306 LocalContext context(NULL, templ);
16307 v8::Handle<v8::Object> global = context->Global();
16309 // Ordinary properties
16310 v8::Handle<v8::String> simple_property =
16311 v8::String::NewFromUtf8(isolate, "p");
16312 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
16313 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16314 // This should fail because the property is dont-delete.
16315 CHECK(!global->Delete(simple_property));
16316 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
16317 // This should succeed even though the property is dont-delete.
16318 CHECK(global->ForceDelete(simple_property));
16319 CHECK(global->Get(simple_property)->IsUndefined());
16323 static int force_delete_interceptor_count = 0;
16324 static bool pass_on_delete = false;
16327 static void ForceDeleteDeleter(
16328 v8::Local<v8::Name> name,
16329 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
16330 force_delete_interceptor_count++;
16331 if (pass_on_delete) return;
16332 info.GetReturnValue().Set(true);
16336 THREADED_TEST(ForceDeleteWithInterceptor) {
16337 force_delete_interceptor_count = 0;
16338 pass_on_delete = false;
16340 v8::Isolate* isolate = CcTest::isolate();
16341 v8::HandleScope scope(isolate);
16342 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
16344 v8::NamedPropertyHandlerConfiguration(0, 0, 0, ForceDeleteDeleter));
16345 LocalContext context(NULL, templ);
16346 v8::Handle<v8::Object> global = context->Global();
16348 v8::Handle<v8::String> some_property =
16349 v8::String::NewFromUtf8(isolate, "a");
16350 global->ForceSet(some_property, v8::Integer::New(isolate, 42),
16353 // Deleting a property should get intercepted and nothing should
16355 CHECK_EQ(0, force_delete_interceptor_count);
16356 CHECK(global->Delete(some_property));
16357 CHECK_EQ(1, force_delete_interceptor_count);
16358 CHECK_EQ(42, global->Get(some_property)->Int32Value());
16359 // Deleting the property when the interceptor returns an empty
16360 // handle should not delete the property since it is DontDelete.
16361 pass_on_delete = true;
16362 CHECK(!global->Delete(some_property));
16363 CHECK_EQ(2, force_delete_interceptor_count);
16364 CHECK_EQ(42, global->Get(some_property)->Int32Value());
16365 // Forcing the property to be deleted should delete the value
16366 // without calling the interceptor.
16367 CHECK(global->ForceDelete(some_property));
16368 CHECK(global->Get(some_property)->IsUndefined());
16369 CHECK_EQ(2, force_delete_interceptor_count);
16373 // Make sure that forcing a delete invalidates any IC stubs, so we
16374 // don't read the hole value.
16375 THREADED_TEST(ForceDeleteIC) {
16376 LocalContext context;
16377 v8::HandleScope scope(context->GetIsolate());
16378 // Create a DontDelete variable on the global object.
16379 CompileRun("this.__proto__ = { foo: 'horse' };"
16380 "var foo = 'fish';"
16381 "function f() { return foo.length; }");
16382 // Initialize the IC for foo in f.
16383 CompileRun("for (var i = 0; i < 4; i++) f();");
16384 // Make sure the value of foo is correct before the deletion.
16385 CHECK_EQ(4, CompileRun("f()")->Int32Value());
16386 // Force the deletion of foo.
16387 CHECK(context->Global()->ForceDelete(v8_str("foo")));
16388 // Make sure the value for foo is read from the prototype, and that
16389 // we don't get in trouble with reading the deleted cell value
16391 CHECK_EQ(5, CompileRun("f()")->Int32Value());
16395 TEST(InlinedFunctionAcrossContexts) {
16396 i::FLAG_allow_natives_syntax = true;
16397 v8::Isolate* isolate = CcTest::isolate();
16398 v8::HandleScope outer_scope(isolate);
16399 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
16400 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
16404 v8::HandleScope inner_scope(CcTest::isolate());
16405 CompileRun("var G = 42; function foo() { return G; }");
16406 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
16408 ctx2->Global()->Set(v8_str("o"), foo);
16409 v8::Local<v8::Value> res = CompileRun(
16410 "function f() { return o(); }"
16411 "for (var i = 0; i < 10; ++i) f();"
16412 "%OptimizeFunctionOnNextCall(f);"
16414 CHECK_EQ(42, res->Int32Value());
16416 v8::Handle<v8::String> G_property =
16417 v8::String::NewFromUtf8(CcTest::isolate(), "G");
16418 CHECK(ctx1->Global()->ForceDelete(G_property));
16425 " return e.toString();"
16428 "ReferenceError: G is not defined");
16435 static v8::Local<Context> calling_context0;
16436 static v8::Local<Context> calling_context1;
16437 static v8::Local<Context> calling_context2;
16440 // Check that the call to the callback is initiated in
16441 // calling_context2, the directly calling context is calling_context1
16442 // and the callback itself is in calling_context0.
16443 static void GetCallingContextCallback(
16444 const v8::FunctionCallbackInfo<v8::Value>& args) {
16445 ApiTestFuzzer::Fuzz();
16446 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
16447 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
16448 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
16449 args.GetReturnValue().Set(42);
16453 THREADED_TEST(GetCurrentContextWhenNotInContext) {
16454 i::Isolate* isolate = CcTest::i_isolate();
16455 CHECK(isolate != NULL);
16456 CHECK(isolate->context() == NULL);
16457 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
16458 v8::HandleScope scope(v8_isolate);
16459 // The following should not crash, but return an empty handle.
16460 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
16461 CHECK(current.IsEmpty());
16465 THREADED_TEST(GetCallingContext) {
16466 v8::Isolate* isolate = CcTest::isolate();
16467 v8::HandleScope scope(isolate);
16469 Local<Context> calling_context0(Context::New(isolate));
16470 Local<Context> calling_context1(Context::New(isolate));
16471 Local<Context> calling_context2(Context::New(isolate));
16472 ::calling_context0 = calling_context0;
16473 ::calling_context1 = calling_context1;
16474 ::calling_context2 = calling_context2;
16476 // Allow cross-domain access.
16477 Local<String> token = v8_str("<security token>");
16478 calling_context0->SetSecurityToken(token);
16479 calling_context1->SetSecurityToken(token);
16480 calling_context2->SetSecurityToken(token);
16482 // Create an object with a C++ callback in context0.
16483 calling_context0->Enter();
16484 Local<v8::FunctionTemplate> callback_templ =
16485 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
16486 calling_context0->Global()->Set(v8_str("callback"),
16487 callback_templ->GetFunction());
16488 calling_context0->Exit();
16490 // Expose context0 in context1 and set up a function that calls the
16491 // callback function.
16492 calling_context1->Enter();
16493 calling_context1->Global()->Set(v8_str("context0"),
16494 calling_context0->Global());
16495 CompileRun("function f() { context0.callback() }");
16496 calling_context1->Exit();
16498 // Expose context1 in context2 and call the callback function in
16499 // context0 indirectly through f in context1.
16500 calling_context2->Enter();
16501 calling_context2->Global()->Set(v8_str("context1"),
16502 calling_context1->Global());
16503 CompileRun("context1.f()");
16504 calling_context2->Exit();
16505 ::calling_context0.Clear();
16506 ::calling_context1.Clear();
16507 ::calling_context2.Clear();
16511 // Check that a variable declaration with no explicit initialization
16512 // value does shadow an existing property in the prototype chain.
16513 THREADED_TEST(InitGlobalVarInProtoChain) {
16514 LocalContext context;
16515 v8::HandleScope scope(context->GetIsolate());
16516 // Introduce a variable in the prototype chain.
16517 CompileRun("__proto__.x = 42");
16518 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
16519 CHECK(!result->IsUndefined());
16520 CHECK_EQ(43, result->Int32Value());
16524 // Regression test for issue 398.
16525 // If a function is added to an object, creating a constant function
16526 // field, and the result is cloned, replacing the constant function on the
16527 // original should not affect the clone.
16528 // See http://code.google.com/p/v8/issues/detail?id=398
16529 THREADED_TEST(ReplaceConstantFunction) {
16530 LocalContext context;
16531 v8::Isolate* isolate = context->GetIsolate();
16532 v8::HandleScope scope(isolate);
16533 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16534 v8::Handle<v8::FunctionTemplate> func_templ =
16535 v8::FunctionTemplate::New(isolate);
16536 v8::Handle<v8::String> foo_string =
16537 v8::String::NewFromUtf8(isolate, "foo");
16538 obj->Set(foo_string, func_templ->GetFunction());
16539 v8::Handle<v8::Object> obj_clone = obj->Clone();
16540 obj_clone->Set(foo_string,
16541 v8::String::NewFromUtf8(isolate, "Hello"));
16542 CHECK(!obj->Get(foo_string)->IsUndefined());
16546 static void CheckElementValue(i::Isolate* isolate,
16548 i::Handle<i::Object> obj,
16550 i::Object* element =
16551 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
16552 CHECK_EQ(expected, i::Smi::cast(element)->value());
16556 THREADED_TEST(PixelArray) {
16557 LocalContext context;
16558 i::Isolate* isolate = CcTest::i_isolate();
16559 i::Factory* factory = isolate->factory();
16560 v8::HandleScope scope(context->GetIsolate());
16561 const int kElementCount = 260;
16562 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16563 i::Handle<i::ExternalUint8ClampedArray> pixels =
16564 i::Handle<i::ExternalUint8ClampedArray>::cast(
16565 factory->NewExternalArray(kElementCount,
16566 v8::kExternalUint8ClampedArray,
16568 // Force GC to trigger verification.
16569 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16570 for (int i = 0; i < kElementCount; i++) {
16571 pixels->set(i, i % 256);
16573 // Force GC to trigger verification.
16574 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16575 for (int i = 0; i < kElementCount; i++) {
16576 CHECK_EQ(i % 256, pixels->get_scalar(i));
16577 CHECK_EQ(i % 256, pixel_data[i]);
16580 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16581 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16582 // Set the elements to be the pixels.
16583 // jsobj->set_elements(*pixels);
16584 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16585 CheckElementValue(isolate, 1, jsobj, 1);
16586 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
16587 context->Global()->Set(v8_str("pixels"), obj);
16588 v8::Handle<v8::Value> result = CompileRun("pixels.field");
16589 CHECK_EQ(1503, result->Int32Value());
16590 result = CompileRun("pixels[1]");
16591 CHECK_EQ(1, result->Int32Value());
16593 result = CompileRun("var sum = 0;"
16594 "for (var i = 0; i < 8; i++) {"
16595 " sum += pixels[i] = pixels[i] = -i;"
16598 CHECK_EQ(-28, result->Int32Value());
16600 result = CompileRun("var sum = 0;"
16601 "for (var i = 0; i < 8; i++) {"
16602 " sum += pixels[i] = pixels[i] = 0;"
16605 CHECK_EQ(0, result->Int32Value());
16607 result = CompileRun("var sum = 0;"
16608 "for (var i = 0; i < 8; i++) {"
16609 " sum += pixels[i] = pixels[i] = 255;"
16612 CHECK_EQ(8 * 255, result->Int32Value());
16614 result = CompileRun("var sum = 0;"
16615 "for (var i = 0; i < 8; i++) {"
16616 " sum += pixels[i] = pixels[i] = 256 + i;"
16619 CHECK_EQ(2076, result->Int32Value());
16621 result = CompileRun("var sum = 0;"
16622 "for (var i = 0; i < 8; i++) {"
16623 " sum += pixels[i] = pixels[i] = i;"
16626 CHECK_EQ(28, result->Int32Value());
16628 result = CompileRun("var sum = 0;"
16629 "for (var i = 0; i < 8; i++) {"
16630 " sum += pixels[i];"
16633 CHECK_EQ(28, result->Int32Value());
16635 i::Handle<i::Smi> value(i::Smi::FromInt(2),
16636 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
16637 i::Handle<i::Object> no_failure;
16638 no_failure = i::JSObject::SetElement(
16639 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16640 DCHECK(!no_failure.is_null());
16642 CheckElementValue(isolate, 2, jsobj, 1);
16643 *value.location() = i::Smi::FromInt(256);
16644 no_failure = i::JSObject::SetElement(
16645 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16646 DCHECK(!no_failure.is_null());
16648 CheckElementValue(isolate, 255, jsobj, 1);
16649 *value.location() = i::Smi::FromInt(-1);
16650 no_failure = i::JSObject::SetElement(
16651 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16652 DCHECK(!no_failure.is_null());
16654 CheckElementValue(isolate, 0, jsobj, 1);
16656 result = CompileRun("for (var i = 0; i < 8; i++) {"
16657 " pixels[i] = (i * 65) - 109;"
16659 "pixels[1] + pixels[6];");
16660 CHECK_EQ(255, result->Int32Value());
16661 CheckElementValue(isolate, 0, jsobj, 0);
16662 CheckElementValue(isolate, 0, jsobj, 1);
16663 CheckElementValue(isolate, 21, jsobj, 2);
16664 CheckElementValue(isolate, 86, jsobj, 3);
16665 CheckElementValue(isolate, 151, jsobj, 4);
16666 CheckElementValue(isolate, 216, jsobj, 5);
16667 CheckElementValue(isolate, 255, jsobj, 6);
16668 CheckElementValue(isolate, 255, jsobj, 7);
16669 result = CompileRun("var sum = 0;"
16670 "for (var i = 0; i < 8; i++) {"
16671 " sum += pixels[i];"
16674 CHECK_EQ(984, result->Int32Value());
16676 result = CompileRun("for (var i = 0; i < 8; i++) {"
16677 " pixels[i] = (i * 1.1);"
16679 "pixels[1] + pixels[6];");
16680 CHECK_EQ(8, result->Int32Value());
16681 CheckElementValue(isolate, 0, jsobj, 0);
16682 CheckElementValue(isolate, 1, jsobj, 1);
16683 CheckElementValue(isolate, 2, jsobj, 2);
16684 CheckElementValue(isolate, 3, jsobj, 3);
16685 CheckElementValue(isolate, 4, jsobj, 4);
16686 CheckElementValue(isolate, 6, jsobj, 5);
16687 CheckElementValue(isolate, 7, jsobj, 6);
16688 CheckElementValue(isolate, 8, jsobj, 7);
16690 result = CompileRun("for (var i = 0; i < 8; i++) {"
16691 " pixels[7] = undefined;"
16694 CHECK_EQ(0, result->Int32Value());
16695 CheckElementValue(isolate, 0, jsobj, 7);
16697 result = CompileRun("for (var i = 0; i < 8; i++) {"
16698 " pixels[6] = '2.3';"
16701 CHECK_EQ(2, result->Int32Value());
16702 CheckElementValue(isolate, 2, jsobj, 6);
16704 result = CompileRun("for (var i = 0; i < 8; i++) {"
16705 " pixels[5] = NaN;"
16708 CHECK_EQ(0, result->Int32Value());
16709 CheckElementValue(isolate, 0, jsobj, 5);
16711 result = CompileRun("for (var i = 0; i < 8; i++) {"
16712 " pixels[8] = Infinity;"
16715 CHECK_EQ(255, result->Int32Value());
16716 CheckElementValue(isolate, 255, jsobj, 8);
16718 result = CompileRun("for (var i = 0; i < 8; i++) {"
16719 " pixels[9] = -Infinity;"
16722 CHECK_EQ(0, result->Int32Value());
16723 CheckElementValue(isolate, 0, jsobj, 9);
16725 result = CompileRun("pixels[3] = 33;"
16726 "delete pixels[3];"
16728 CHECK_EQ(33, result->Int32Value());
16730 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
16731 "pixels[2] = 12; pixels[3] = 13;"
16732 "pixels.__defineGetter__('2',"
16733 "function() { return 120; });"
16735 CHECK_EQ(12, result->Int32Value());
16737 result = CompileRun("var js_array = new Array(40);"
16738 "js_array[0] = 77;"
16740 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16742 result = CompileRun("pixels[1] = 23;"
16743 "pixels.__proto__ = [];"
16744 "js_array.__proto__ = pixels;"
16745 "js_array.concat(pixels);");
16746 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16747 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16749 result = CompileRun("pixels[1] = 23;");
16750 CHECK_EQ(23, result->Int32Value());
16752 // Test for index greater than 255. Regression test for:
16753 // http://code.google.com/p/chromium/issues/detail?id=26337.
16754 result = CompileRun("pixels[256] = 255;");
16755 CHECK_EQ(255, result->Int32Value());
16756 result = CompileRun("var i = 0;"
16757 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
16759 CHECK_EQ(255, result->Int32Value());
16761 // Make sure that pixel array ICs recognize when a non-pixel array
16762 // is passed to it.
16763 result = CompileRun("function pa_load(p) {"
16765 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16768 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16769 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16770 "just_ints = new Object();"
16771 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16772 "for (var i = 0; i < 10; ++i) {"
16773 " result = pa_load(just_ints);"
16776 CHECK_EQ(32640, result->Int32Value());
16778 // Make sure that pixel array ICs recognize out-of-bound accesses.
16779 result = CompileRun("function pa_load(p, start) {"
16781 " for (var j = start; j < 256; j++) { sum += p[j]; }"
16784 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16785 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16786 "for (var i = 0; i < 10; ++i) {"
16787 " result = pa_load(pixels,-10);"
16790 CHECK_EQ(0, result->Int32Value());
16792 // Make sure that generic ICs properly handles a pixel array.
16793 result = CompileRun("function pa_load(p) {"
16795 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16798 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16799 "just_ints = new Object();"
16800 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16801 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16802 "for (var i = 0; i < 10; ++i) {"
16803 " result = pa_load(pixels);"
16806 CHECK_EQ(32640, result->Int32Value());
16808 // Make sure that generic load ICs recognize out-of-bound accesses in
16810 result = CompileRun("function pa_load(p, start) {"
16812 " for (var j = start; j < 256; j++) { sum += p[j]; }"
16815 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16816 "just_ints = new Object();"
16817 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16818 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16819 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16820 "for (var i = 0; i < 10; ++i) {"
16821 " result = pa_load(pixels,-10);"
16824 CHECK_EQ(0, result->Int32Value());
16826 // Make sure that generic ICs properly handles other types than pixel
16827 // arrays (that the inlined fast pixel array test leaves the right information
16828 // in the right registers).
16829 result = CompileRun("function pa_load(p) {"
16831 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16834 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16835 "just_ints = new Object();"
16836 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16837 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16838 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16839 "sparse_array = new Object();"
16840 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16841 "sparse_array[1000000] = 3;"
16842 "for (var i = 0; i < 10; ++i) {"
16843 " result = pa_load(sparse_array);"
16846 CHECK_EQ(32640, result->Int32Value());
16848 // Make sure that pixel array store ICs clamp values correctly.
16849 result = CompileRun("function pa_store(p) {"
16850 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16852 "pa_store(pixels);"
16854 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16856 CHECK_EQ(48896, result->Int32Value());
16858 // Make sure that pixel array stores correctly handle accesses outside
16859 // of the pixel array..
16860 result = CompileRun("function pa_store(p,start) {"
16861 " for (var j = 0; j < 256; j++) {"
16862 " p[j+start] = j * 2;"
16865 "pa_store(pixels,0);"
16866 "pa_store(pixels,-128);"
16868 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16870 CHECK_EQ(65280, result->Int32Value());
16872 // Make sure that the generic store stub correctly handle accesses outside
16873 // of the pixel array..
16874 result = CompileRun("function pa_store(p,start) {"
16875 " for (var j = 0; j < 256; j++) {"
16876 " p[j+start] = j * 2;"
16879 "pa_store(pixels,0);"
16880 "just_ints = new Object();"
16881 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16882 "pa_store(just_ints, 0);"
16883 "pa_store(pixels,-128);"
16885 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16887 CHECK_EQ(65280, result->Int32Value());
16889 // Make sure that the generic keyed store stub clamps pixel array values
16891 result = CompileRun("function pa_store(p) {"
16892 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16894 "pa_store(pixels);"
16895 "just_ints = new Object();"
16896 "pa_store(just_ints);"
16897 "pa_store(pixels);"
16899 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16901 CHECK_EQ(48896, result->Int32Value());
16903 // Make sure that pixel array loads are optimized by crankshaft.
16904 result = CompileRun("function pa_load(p) {"
16906 " for (var i=0; i<256; ++i) {"
16911 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16912 "for (var i = 0; i < 5000; ++i) {"
16913 " result = pa_load(pixels);"
16916 CHECK_EQ(32640, result->Int32Value());
16918 // Make sure that pixel array stores are optimized by crankshaft.
16919 result = CompileRun("function pa_init(p) {"
16920 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16922 "function pa_load(p) {"
16924 " for (var i=0; i<256; ++i) {"
16929 "for (var i = 0; i < 5000; ++i) {"
16930 " pa_init(pixels);"
16932 "result = pa_load(pixels);"
16934 CHECK_EQ(32640, result->Int32Value());
16940 THREADED_TEST(PixelArrayInfo) {
16941 LocalContext context;
16942 v8::HandleScope scope(context->GetIsolate());
16943 for (int size = 0; size < 100; size += 10) {
16944 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16945 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16946 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16947 CHECK(obj->HasIndexedPropertiesInPixelData());
16948 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16949 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16955 static void NotHandledIndexedPropertyGetter(
16957 const v8::PropertyCallbackInfo<v8::Value>& info) {
16958 ApiTestFuzzer::Fuzz();
16962 static void NotHandledIndexedPropertySetter(
16964 Local<Value> value,
16965 const v8::PropertyCallbackInfo<v8::Value>& info) {
16966 ApiTestFuzzer::Fuzz();
16970 THREADED_TEST(PixelArrayWithInterceptor) {
16971 LocalContext context;
16972 i::Factory* factory = CcTest::i_isolate()->factory();
16973 v8::Isolate* isolate = context->GetIsolate();
16974 v8::HandleScope scope(isolate);
16975 const int kElementCount = 260;
16976 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16977 i::Handle<i::ExternalUint8ClampedArray> pixels =
16978 i::Handle<i::ExternalUint8ClampedArray>::cast(
16979 factory->NewExternalArray(kElementCount,
16980 v8::kExternalUint8ClampedArray,
16982 for (int i = 0; i < kElementCount; i++) {
16983 pixels->set(i, i % 256);
16985 v8::Handle<v8::ObjectTemplate> templ =
16986 v8::ObjectTemplate::New(context->GetIsolate());
16987 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
16988 NotHandledIndexedPropertyGetter, NotHandledIndexedPropertySetter));
16989 v8::Handle<v8::Object> obj = templ->NewInstance();
16990 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16991 context->Global()->Set(v8_str("pixels"), obj);
16992 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16993 CHECK_EQ(1, result->Int32Value());
16994 result = CompileRun("var sum = 0;"
16995 "for (var i = 0; i < 8; i++) {"
16996 " sum += pixels[i] = pixels[i] = -i;"
16999 CHECK_EQ(-28, result->Int32Value());
17000 result = CompileRun("pixels.hasOwnProperty('1')");
17001 CHECK(result->BooleanValue());
17006 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
17007 switch (array_type) {
17008 case v8::kExternalInt8Array:
17009 case v8::kExternalUint8Array:
17010 case v8::kExternalUint8ClampedArray:
17013 case v8::kExternalInt16Array:
17014 case v8::kExternalUint16Array:
17017 case v8::kExternalInt32Array:
17018 case v8::kExternalUint32Array:
17019 case v8::kExternalFloat32Array:
17022 case v8::kExternalFloat64Array:
17034 template <class ExternalArrayClass, class ElementType>
17035 static void ObjectWithExternalArrayTestHelper(
17036 Handle<Context> context,
17037 v8::Handle<Object> obj,
17039 v8::ExternalArrayType array_type,
17040 int64_t low, int64_t high) {
17041 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17042 i::Isolate* isolate = jsobj->GetIsolate();
17043 obj->Set(v8_str("field"),
17044 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
17045 context->Global()->Set(v8_str("ext_array"), obj);
17046 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
17047 CHECK_EQ(1503, result->Int32Value());
17048 result = CompileRun("ext_array[1]");
17049 CHECK_EQ(1, result->Int32Value());
17051 // Check assigned smis
17052 result = CompileRun("for (var i = 0; i < 8; i++) {"
17053 " ext_array[i] = i;"
17056 "for (var i = 0; i < 8; i++) {"
17057 " sum += ext_array[i];"
17061 CHECK_EQ(28, result->Int32Value());
17062 // Check pass through of assigned smis
17063 result = CompileRun("var sum = 0;"
17064 "for (var i = 0; i < 8; i++) {"
17065 " sum += ext_array[i] = ext_array[i] = -i;"
17068 CHECK_EQ(-28, result->Int32Value());
17071 // Check assigned smis in reverse order
17072 result = CompileRun("for (var i = 8; --i >= 0; ) {"
17073 " ext_array[i] = i;"
17076 "for (var i = 0; i < 8; i++) {"
17077 " sum += ext_array[i];"
17080 CHECK_EQ(28, result->Int32Value());
17082 // Check pass through of assigned HeapNumbers
17083 result = CompileRun("var sum = 0;"
17084 "for (var i = 0; i < 16; i+=2) {"
17085 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
17088 CHECK_EQ(-28, result->Int32Value());
17090 // Check assigned HeapNumbers
17091 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
17092 " ext_array[i] = (i * 0.5);"
17095 "for (var i = 0; i < 16; i+=2) {"
17096 " sum += ext_array[i];"
17099 CHECK_EQ(28, result->Int32Value());
17101 // Check assigned HeapNumbers in reverse order
17102 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
17103 " ext_array[i] = (i * 0.5);"
17106 "for (var i = 0; i < 16; i+=2) {"
17107 " sum += ext_array[i];"
17110 CHECK_EQ(28, result->Int32Value());
17112 i::ScopedVector<char> test_buf(1024);
17114 // Check legal boundary conditions.
17115 // The repeated loads and stores ensure the ICs are exercised.
17116 const char* boundary_program =
17118 "for (var i = 0; i < 16; i++) {"
17119 " ext_array[i] = %lld;"
17121 " res = ext_array[i];"
17125 i::SNPrintF(test_buf,
17128 result = CompileRun(test_buf.start());
17129 CHECK_EQ(low, result->IntegerValue());
17131 i::SNPrintF(test_buf,
17134 result = CompileRun(test_buf.start());
17135 CHECK_EQ(high, result->IntegerValue());
17137 // Check misprediction of type in IC.
17138 result = CompileRun("var tmp_array = ext_array;"
17140 "for (var i = 0; i < 8; i++) {"
17141 " tmp_array[i] = i;"
17142 " sum += tmp_array[i];"
17148 // Force GC to trigger verification.
17149 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17150 CHECK_EQ(28, result->Int32Value());
17152 // Make sure out-of-range loads do not throw.
17153 i::SNPrintF(test_buf,
17154 "var caught_exception = false;"
17158 " caught_exception = true;"
17160 "caught_exception;",
17162 result = CompileRun(test_buf.start());
17163 CHECK_EQ(false, result->BooleanValue());
17165 // Make sure out-of-range stores do not throw.
17166 i::SNPrintF(test_buf,
17167 "var caught_exception = false;"
17169 " ext_array[%d] = 1;"
17171 " caught_exception = true;"
17173 "caught_exception;",
17175 result = CompileRun(test_buf.start());
17176 CHECK_EQ(false, result->BooleanValue());
17178 // Check other boundary conditions, values and operations.
17179 result = CompileRun("for (var i = 0; i < 8; i++) {"
17180 " ext_array[7] = undefined;"
17183 CHECK_EQ(0, result->Int32Value());
17184 if (array_type == v8::kExternalFloat64Array ||
17185 array_type == v8::kExternalFloat32Array) {
17186 CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
17188 i::Object::GetElement(
17189 isolate, jsobj, 7).ToHandleChecked()->Number()));
17191 CheckElementValue(isolate, 0, jsobj, 7);
17194 result = CompileRun("for (var i = 0; i < 8; i++) {"
17195 " ext_array[6] = '2.3';"
17198 CHECK_EQ(2, result->Int32Value());
17201 i::Object::GetElement(
17202 isolate, jsobj, 6).ToHandleChecked()->Number()));
17204 if (array_type != v8::kExternalFloat32Array &&
17205 array_type != v8::kExternalFloat64Array) {
17206 // Though the specification doesn't state it, be explicit about
17207 // converting NaNs and +/-Infinity to zero.
17208 result = CompileRun("for (var i = 0; i < 8; i++) {"
17209 " ext_array[i] = 5;"
17211 "for (var i = 0; i < 8; i++) {"
17212 " ext_array[i] = NaN;"
17215 CHECK_EQ(0, result->Int32Value());
17216 CheckElementValue(isolate, 0, jsobj, 5);
17218 result = CompileRun("for (var i = 0; i < 8; i++) {"
17219 " ext_array[i] = 5;"
17221 "for (var i = 0; i < 8; i++) {"
17222 " ext_array[i] = Infinity;"
17225 int expected_value =
17226 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
17227 CHECK_EQ(expected_value, result->Int32Value());
17228 CheckElementValue(isolate, expected_value, jsobj, 5);
17230 result = CompileRun("for (var i = 0; i < 8; i++) {"
17231 " ext_array[i] = 5;"
17233 "for (var i = 0; i < 8; i++) {"
17234 " ext_array[i] = -Infinity;"
17237 CHECK_EQ(0, result->Int32Value());
17238 CheckElementValue(isolate, 0, jsobj, 5);
17240 // Check truncation behavior of integral arrays.
17241 const char* unsigned_data =
17242 "var source_data = [0.6, 10.6];"
17243 "var expected_results = [0, 10];";
17244 const char* signed_data =
17245 "var source_data = [0.6, 10.6, -0.6, -10.6];"
17246 "var expected_results = [0, 10, 0, -10];";
17247 const char* pixel_data =
17248 "var source_data = [0.6, 10.6];"
17249 "var expected_results = [1, 11];";
17251 (array_type == v8::kExternalUint8Array ||
17252 array_type == v8::kExternalUint16Array ||
17253 array_type == v8::kExternalUint32Array);
17254 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
17256 i::SNPrintF(test_buf,
17258 "var all_passed = true;"
17259 "for (var i = 0; i < source_data.length; i++) {"
17260 " for (var j = 0; j < 8; j++) {"
17261 " ext_array[j] = source_data[i];"
17263 " all_passed = all_passed &&"
17264 " (ext_array[5] == expected_results[i]);"
17269 (is_pixel_data ? pixel_data : signed_data)));
17270 result = CompileRun(test_buf.start());
17271 CHECK_EQ(true, result->BooleanValue());
17274 i::Handle<ExternalArrayClass> array(
17275 ExternalArrayClass::cast(jsobj->elements()));
17276 for (int i = 0; i < element_count; i++) {
17277 array->set(i, static_cast<ElementType>(i));
17280 // Test complex assignments
17281 result = CompileRun("function ee_op_test_complex_func(sum) {"
17282 " for (var i = 0; i < 40; ++i) {"
17283 " sum += (ext_array[i] += 1);"
17284 " sum += (ext_array[i] -= 1);"
17289 "for (var i=0;i<10000;++i) {"
17290 " sum=ee_op_test_complex_func(sum);"
17293 CHECK_EQ(16000000, result->Int32Value());
17295 // Test count operations
17296 result = CompileRun("function ee_op_test_count_func(sum) {"
17297 " for (var i = 0; i < 40; ++i) {"
17298 " sum += (++ext_array[i]);"
17299 " sum += (--ext_array[i]);"
17304 "for (var i=0;i<10000;++i) {"
17305 " sum=ee_op_test_count_func(sum);"
17308 CHECK_EQ(16000000, result->Int32Value());
17310 result = CompileRun("ext_array[3] = 33;"
17311 "delete ext_array[3];"
17313 CHECK_EQ(33, result->Int32Value());
17315 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
17316 "ext_array[2] = 12; ext_array[3] = 13;"
17317 "ext_array.__defineGetter__('2',"
17318 "function() { return 120; });"
17320 CHECK_EQ(12, result->Int32Value());
17322 result = CompileRun("var js_array = new Array(40);"
17323 "js_array[0] = 77;"
17325 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
17327 result = CompileRun("ext_array[1] = 23;"
17328 "ext_array.__proto__ = [];"
17329 "js_array.__proto__ = ext_array;"
17330 "js_array.concat(ext_array);");
17331 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
17332 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
17334 result = CompileRun("ext_array[1] = 23;");
17335 CHECK_EQ(23, result->Int32Value());
17339 template <class FixedTypedArrayClass,
17340 i::ElementsKind elements_kind,
17342 static void FixedTypedArrayTestHelper(
17343 v8::ExternalArrayType array_type,
17345 ElementType high) {
17346 i::FLAG_allow_natives_syntax = true;
17347 LocalContext context;
17348 i::Isolate* isolate = CcTest::i_isolate();
17349 i::Factory* factory = isolate->factory();
17350 v8::HandleScope scope(context->GetIsolate());
17351 const int kElementCount = 260;
17352 i::Handle<FixedTypedArrayClass> fixed_array =
17353 i::Handle<FixedTypedArrayClass>::cast(
17354 factory->NewFixedTypedArray(kElementCount, array_type));
17355 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
17356 fixed_array->map()->instance_type());
17357 CHECK_EQ(kElementCount, fixed_array->length());
17358 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17359 for (int i = 0; i < kElementCount; i++) {
17360 fixed_array->set(i, static_cast<ElementType>(i));
17362 // Force GC to trigger verification.
17363 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17364 for (int i = 0; i < kElementCount; i++) {
17365 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
17366 static_cast<int64_t>(fixed_array->get_scalar(i)));
17368 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
17369 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17370 i::Handle<i::Map> fixed_array_map =
17371 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
17372 jsobj->set_map(*fixed_array_map);
17373 jsobj->set_elements(*fixed_array);
17375 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
17376 context.local(), obj, kElementCount, array_type,
17377 static_cast<int64_t>(low),
17378 static_cast<int64_t>(high));
17382 THREADED_TEST(FixedUint8Array) {
17383 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
17384 v8::kExternalUint8Array,
17389 THREADED_TEST(FixedUint8ClampedArray) {
17390 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
17391 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
17392 v8::kExternalUint8ClampedArray,
17397 THREADED_TEST(FixedInt8Array) {
17398 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
17399 v8::kExternalInt8Array,
17404 THREADED_TEST(FixedUint16Array) {
17405 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
17406 v8::kExternalUint16Array,
17411 THREADED_TEST(FixedInt16Array) {
17412 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
17413 v8::kExternalInt16Array,
17418 THREADED_TEST(FixedUint32Array) {
17419 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
17420 v8::kExternalUint32Array,
17425 THREADED_TEST(FixedInt32Array) {
17426 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
17427 v8::kExternalInt32Array,
17432 THREADED_TEST(FixedFloat32Array) {
17433 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
17434 v8::kExternalFloat32Array,
17439 THREADED_TEST(FixedFloat64Array) {
17440 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
17441 v8::kExternalFloat64Array,
17446 template <class ExternalArrayClass, class ElementType>
17447 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
17450 LocalContext context;
17451 i::Isolate* isolate = CcTest::i_isolate();
17452 i::Factory* factory = isolate->factory();
17453 v8::HandleScope scope(context->GetIsolate());
17454 const int kElementCount = 40;
17455 int element_size = ExternalArrayElementSize(array_type);
17456 ElementType* array_data =
17457 static_cast<ElementType*>(malloc(kElementCount * element_size));
17458 i::Handle<ExternalArrayClass> array =
17459 i::Handle<ExternalArrayClass>::cast(
17460 factory->NewExternalArray(kElementCount, array_type, array_data));
17461 // Force GC to trigger verification.
17462 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17463 for (int i = 0; i < kElementCount; i++) {
17464 array->set(i, static_cast<ElementType>(i));
17466 // Force GC to trigger verification.
17467 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17468 for (int i = 0; i < kElementCount; i++) {
17469 CHECK_EQ(static_cast<int64_t>(i),
17470 static_cast<int64_t>(array->get_scalar(i)));
17471 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
17474 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17475 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17476 // Set the elements to be the external array.
17477 obj->SetIndexedPropertiesToExternalArrayData(array_data,
17482 i::Object::GetElement(
17483 isolate, jsobj, 1).ToHandleChecked()->Number()));
17485 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17486 context.local(), obj, kElementCount, array_type, low, high);
17488 v8::Handle<v8::Value> result;
17490 // Test more complex manipulations which cause eax to contain values
17491 // that won't be completely overwritten by loads from the arrays.
17492 // This catches bugs in the instructions used for the KeyedLoadIC
17493 // for byte and word types.
17495 const int kXSize = 300;
17496 const int kYSize = 300;
17497 const int kLargeElementCount = kXSize * kYSize * 4;
17498 ElementType* large_array_data =
17499 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
17500 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
17501 // Set the elements to be the external array.
17502 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
17504 kLargeElementCount);
17505 context->Global()->Set(v8_str("large_array"), large_obj);
17506 // Initialize contents of a few rows.
17507 for (int x = 0; x < 300; x++) {
17509 int offset = row * 300 * 4;
17510 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17511 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17512 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17513 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17515 offset = row * 300 * 4;
17516 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17517 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17518 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17519 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17521 offset = row * 300 * 4;
17522 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17523 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17524 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17525 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17527 // The goal of the code below is to make "offset" large enough
17528 // that the computation of the index (which goes into eax) has
17529 // high bits set which will not be overwritten by a byte or short
17531 result = CompileRun("var failed = false;"
17533 "for (var i = 0; i < 300; i++) {"
17534 " if (large_array[4 * i] != 127 ||"
17535 " large_array[4 * i + 1] != 0 ||"
17536 " large_array[4 * i + 2] != 0 ||"
17537 " large_array[4 * i + 3] != 127) {"
17541 "offset = 150 * 300 * 4;"
17542 "for (var i = 0; i < 300; i++) {"
17543 " if (large_array[offset + 4 * i] != 127 ||"
17544 " large_array[offset + 4 * i + 1] != 0 ||"
17545 " large_array[offset + 4 * i + 2] != 0 ||"
17546 " large_array[offset + 4 * i + 3] != 127) {"
17550 "offset = 298 * 300 * 4;"
17551 "for (var i = 0; i < 300; i++) {"
17552 " if (large_array[offset + 4 * i] != 127 ||"
17553 " large_array[offset + 4 * i + 1] != 0 ||"
17554 " large_array[offset + 4 * i + 2] != 0 ||"
17555 " large_array[offset + 4 * i + 3] != 127) {"
17560 CHECK_EQ(true, result->BooleanValue());
17561 free(large_array_data);
17564 // The "" property descriptor is overloaded to store information about
17565 // the external array. Ensure that setting and accessing the "" property
17566 // works (it should overwrite the information cached about the external
17567 // array in the DescriptorArray) in various situations.
17568 result = CompileRun("ext_array[''] = 23; ext_array['']");
17569 CHECK_EQ(23, result->Int32Value());
17571 // Property "" set after the external array is associated with the object.
17573 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17574 obj2->Set(v8_str("ee_test_field"),
17575 v8::Int32::New(context->GetIsolate(), 256));
17576 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
17577 // Set the elements to be the external array.
17578 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17581 context->Global()->Set(v8_str("ext_array"), obj2);
17582 result = CompileRun("ext_array['']");
17583 CHECK_EQ(1503, result->Int32Value());
17586 // Property "" set after the external array is associated with the object.
17588 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17589 obj2->Set(v8_str("ee_test_field_2"),
17590 v8::Int32::New(context->GetIsolate(), 256));
17591 // Set the elements to be the external array.
17592 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17595 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
17596 context->Global()->Set(v8_str("ext_array"), obj2);
17597 result = CompileRun("ext_array['']");
17598 CHECK_EQ(1503, result->Int32Value());
17601 // Should reuse the map from previous test.
17603 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17604 obj2->Set(v8_str("ee_test_field_2"),
17605 v8::Int32::New(context->GetIsolate(), 256));
17606 // Set the elements to be the external array. Should re-use the map
17607 // from previous test.
17608 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17611 context->Global()->Set(v8_str("ext_array"), obj2);
17612 result = CompileRun("ext_array['']");
17615 // Property "" is a constant function that shouldn't not be interfered with
17616 // when an external array is set.
17618 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17620 obj2->Set(v8_str("ee_test_field3"),
17621 v8::Int32::New(context->GetIsolate(), 256));
17623 // Add a constant function to an object.
17624 context->Global()->Set(v8_str("ext_array"), obj2);
17625 result = CompileRun("ext_array[''] = function() {return 1503;};"
17626 "ext_array['']();");
17628 // Add an external array transition to the same map that
17629 // has the constant transition.
17630 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
17631 obj3->Set(v8_str("ee_test_field3"),
17632 v8::Int32::New(context->GetIsolate(), 256));
17633 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
17636 context->Global()->Set(v8_str("ext_array"), obj3);
17639 // If a external array transition is in the map, it should get clobbered
17640 // by a constant function.
17642 // Add an external array transition.
17643 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
17644 obj3->Set(v8_str("ee_test_field4"),
17645 v8::Int32::New(context->GetIsolate(), 256));
17646 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
17650 // Add a constant function to the same map that just got an external array
17652 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17653 obj2->Set(v8_str("ee_test_field4"),
17654 v8::Int32::New(context->GetIsolate(), 256));
17655 context->Global()->Set(v8_str("ext_array"), obj2);
17656 result = CompileRun("ext_array[''] = function() {return 1503;};"
17657 "ext_array['']();");
17664 THREADED_TEST(ExternalInt8Array) {
17665 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
17666 v8::kExternalInt8Array,
17672 THREADED_TEST(ExternalUint8Array) {
17673 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
17674 v8::kExternalUint8Array,
17680 THREADED_TEST(ExternalUint8ClampedArray) {
17681 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
17682 v8::kExternalUint8ClampedArray,
17688 THREADED_TEST(ExternalInt16Array) {
17689 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
17690 v8::kExternalInt16Array,
17696 THREADED_TEST(ExternalUint16Array) {
17697 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
17698 v8::kExternalUint16Array,
17704 THREADED_TEST(ExternalInt32Array) {
17705 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
17706 v8::kExternalInt32Array,
17707 INT_MIN, // -2147483648
17708 INT_MAX); // 2147483647
17712 THREADED_TEST(ExternalUint32Array) {
17713 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
17714 v8::kExternalUint32Array,
17716 UINT_MAX); // 4294967295
17720 THREADED_TEST(ExternalFloat32Array) {
17721 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
17722 v8::kExternalFloat32Array,
17728 THREADED_TEST(ExternalFloat64Array) {
17729 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
17730 v8::kExternalFloat64Array,
17736 THREADED_TEST(ExternalArrays) {
17737 TestExternalInt8Array();
17738 TestExternalUint8Array();
17739 TestExternalInt16Array();
17740 TestExternalUint16Array();
17741 TestExternalInt32Array();
17742 TestExternalUint32Array();
17743 TestExternalFloat32Array();
17747 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
17748 LocalContext context;
17749 v8::HandleScope scope(context->GetIsolate());
17750 for (int size = 0; size < 100; size += 10) {
17751 int element_size = ExternalArrayElementSize(array_type);
17752 void* external_data = malloc(size * element_size);
17753 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17754 obj->SetIndexedPropertiesToExternalArrayData(
17755 external_data, array_type, size);
17756 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
17757 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
17758 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
17759 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
17760 free(external_data);
17765 THREADED_TEST(ExternalArrayInfo) {
17766 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
17767 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
17768 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
17769 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
17770 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
17771 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
17772 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
17773 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
17774 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
17778 void ExtArrayLimitsHelper(v8::Isolate* isolate,
17779 v8::ExternalArrayType array_type,
17781 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
17782 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17783 last_location = last_message = NULL;
17784 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
17785 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
17786 CHECK_NE(NULL, last_location);
17787 CHECK_NE(NULL, last_message);
17791 TEST(ExternalArrayLimits) {
17792 LocalContext context;
17793 v8::Isolate* isolate = context->GetIsolate();
17794 v8::HandleScope scope(isolate);
17795 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
17796 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
17797 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
17798 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
17799 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
17800 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
17801 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
17802 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
17803 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
17804 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
17805 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17806 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17807 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17808 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17809 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17810 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17811 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17812 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17816 template <typename ElementType, typename TypedArray,
17817 class ExternalArrayClass>
17818 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17819 int64_t low, int64_t high) {
17820 const int kElementCount = 50;
17822 i::ScopedVector<ElementType> backing_store(kElementCount+2);
17825 v8::Isolate* isolate = env->GetIsolate();
17826 v8::HandleScope handle_scope(isolate);
17828 Local<v8::ArrayBuffer> ab =
17829 v8::ArrayBuffer::New(isolate, backing_store.start(),
17830 (kElementCount + 2) * sizeof(ElementType));
17831 Local<TypedArray> ta =
17832 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17833 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17834 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17835 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17836 CHECK_EQ(kElementCount*sizeof(ElementType),
17837 static_cast<int>(ta->ByteLength()));
17838 CHECK_EQ(ab, ta->Buffer());
17840 ElementType* data = backing_store.start() + 2;
17841 for (int i = 0; i < kElementCount; i++) {
17842 data[i] = static_cast<ElementType>(i);
17845 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17846 env.local(), ta, kElementCount, array_type, low, high);
17850 THREADED_TEST(Uint8Array) {
17851 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17852 v8::kExternalUint8Array, 0, 0xFF);
17856 THREADED_TEST(Int8Array) {
17857 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17858 v8::kExternalInt8Array, -0x80, 0x7F);
17862 THREADED_TEST(Uint16Array) {
17863 TypedArrayTestHelper<uint16_t,
17865 i::ExternalUint16Array>(
17866 v8::kExternalUint16Array, 0, 0xFFFF);
17870 THREADED_TEST(Int16Array) {
17871 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17872 v8::kExternalInt16Array, -0x8000, 0x7FFF);
17876 THREADED_TEST(Uint32Array) {
17877 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17878 v8::kExternalUint32Array, 0, UINT_MAX);
17882 THREADED_TEST(Int32Array) {
17883 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17884 v8::kExternalInt32Array, INT_MIN, INT_MAX);
17888 THREADED_TEST(Float32Array) {
17889 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17890 v8::kExternalFloat32Array, -500, 500);
17894 THREADED_TEST(Float64Array) {
17895 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17896 v8::kExternalFloat64Array, -500, 500);
17900 THREADED_TEST(Uint8ClampedArray) {
17901 TypedArrayTestHelper<uint8_t,
17902 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17903 v8::kExternalUint8ClampedArray, 0, 0xFF);
17907 THREADED_TEST(DataView) {
17908 const int kSize = 50;
17910 i::ScopedVector<uint8_t> backing_store(kSize+2);
17913 v8::Isolate* isolate = env->GetIsolate();
17914 v8::HandleScope handle_scope(isolate);
17916 Local<v8::ArrayBuffer> ab =
17917 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17918 Local<v8::DataView> dv =
17919 v8::DataView::New(ab, 2, kSize);
17920 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17921 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17922 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17923 CHECK_EQ(ab, dv->Buffer());
17927 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
17928 THREADED_TEST(Is##View) { \
17929 LocalContext env; \
17930 v8::Isolate* isolate = env->GetIsolate(); \
17931 v8::HandleScope handle_scope(isolate); \
17933 Handle<Value> result = CompileRun( \
17934 "var ab = new ArrayBuffer(128);" \
17935 "new " #View "(ab)"); \
17936 CHECK(result->IsArrayBufferView()); \
17937 CHECK(result->Is##View()); \
17938 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17941 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17942 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17943 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17944 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17945 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17946 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17947 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17948 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17949 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17950 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17952 #undef IS_ARRAY_BUFFER_VIEW_TEST
17956 THREADED_TEST(ScriptContextDependence) {
17958 v8::HandleScope scope(c1->GetIsolate());
17959 const char *source = "foo";
17960 v8::Handle<v8::Script> dep = v8_compile(source);
17961 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17962 c1->GetIsolate(), source));
17963 v8::Handle<v8::UnboundScript> indep =
17964 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17965 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17966 v8::Integer::New(c1->GetIsolate(), 100));
17967 CHECK_EQ(dep->Run()->Int32Value(), 100);
17968 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17970 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17971 v8::Integer::New(c2->GetIsolate(), 101));
17972 CHECK_EQ(dep->Run()->Int32Value(), 100);
17973 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17977 THREADED_TEST(StackTrace) {
17978 LocalContext context;
17979 v8::HandleScope scope(context->GetIsolate());
17980 v8::TryCatch try_catch;
17981 const char *source = "function foo() { FAIL.FAIL; }; foo();";
17982 v8::Handle<v8::String> src =
17983 v8::String::NewFromUtf8(context->GetIsolate(), source);
17984 v8::Handle<v8::String> origin =
17985 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17986 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17987 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17988 ->BindToCurrentContext()
17990 CHECK(try_catch.HasCaught());
17991 v8::String::Utf8Value stack(try_catch.StackTrace());
17992 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17996 // Checks that a StackFrame has certain expected values.
17997 void checkStackFrame(const char* expected_script_name,
17998 const char* expected_func_name, int expected_line_number,
17999 int expected_column, bool is_eval, bool is_constructor,
18000 v8::Handle<v8::StackFrame> frame) {
18001 v8::HandleScope scope(CcTest::isolate());
18002 v8::String::Utf8Value func_name(frame->GetFunctionName());
18003 v8::String::Utf8Value script_name(frame->GetScriptName());
18004 if (*script_name == NULL) {
18005 // The situation where there is no associated script, like for evals.
18006 CHECK(expected_script_name == NULL);
18008 CHECK(strstr(*script_name, expected_script_name) != NULL);
18010 CHECK(strstr(*func_name, expected_func_name) != NULL);
18011 CHECK_EQ(expected_line_number, frame->GetLineNumber());
18012 CHECK_EQ(expected_column, frame->GetColumn());
18013 CHECK_EQ(is_eval, frame->IsEval());
18014 CHECK_EQ(is_constructor, frame->IsConstructor());
18018 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
18019 v8::HandleScope scope(args.GetIsolate());
18020 const char* origin = "capture-stack-trace-test";
18021 const int kOverviewTest = 1;
18022 const int kDetailedTest = 2;
18024 DCHECK(args.Length() == 1);
18026 int testGroup = args[0]->Int32Value();
18027 if (testGroup == kOverviewTest) {
18028 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18029 args.GetIsolate(), 10, v8::StackTrace::kOverview);
18030 CHECK_EQ(4, stackTrace->GetFrameCount());
18031 checkStackFrame(origin, "bar", 2, 10, false, false,
18032 stackTrace->GetFrame(0));
18033 checkStackFrame(origin, "foo", 6, 3, false, false,
18034 stackTrace->GetFrame(1));
18035 // This is the source string inside the eval which has the call to foo.
18036 checkStackFrame(NULL, "", 1, 5, false, false,
18037 stackTrace->GetFrame(2));
18038 // The last frame is an anonymous function which has the initial eval call.
18039 checkStackFrame(origin, "", 8, 7, false, false,
18040 stackTrace->GetFrame(3));
18042 CHECK(stackTrace->AsArray()->IsArray());
18043 } else if (testGroup == kDetailedTest) {
18044 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18045 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18046 CHECK_EQ(4, stackTrace->GetFrameCount());
18047 checkStackFrame(origin, "bat", 4, 22, false, false,
18048 stackTrace->GetFrame(0));
18049 checkStackFrame(origin, "baz", 8, 3, false, true,
18050 stackTrace->GetFrame(1));
18051 bool is_eval = true;
18052 // This is the source string inside the eval which has the call to baz.
18053 checkStackFrame(NULL, "", 1, 5, is_eval, false,
18054 stackTrace->GetFrame(2));
18055 // The last frame is an anonymous function which has the initial eval call.
18056 checkStackFrame(origin, "", 10, 1, false, false,
18057 stackTrace->GetFrame(3));
18059 CHECK(stackTrace->AsArray()->IsArray());
18064 // Tests the C++ StackTrace API.
18065 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
18066 // THREADED_TEST(CaptureStackTrace) {
18067 TEST(CaptureStackTrace) {
18068 v8::Isolate* isolate = CcTest::isolate();
18069 v8::HandleScope scope(isolate);
18070 v8::Handle<v8::String> origin =
18071 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
18072 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18073 templ->Set(v8_str("AnalyzeStackInNativeCode"),
18074 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
18075 LocalContext context(0, templ);
18077 // Test getting OVERVIEW information. Should ignore information that is not
18078 // script name, function name, line number, and column offset.
18079 const char *overview_source =
18080 "function bar() {\n"
18081 " var y; AnalyzeStackInNativeCode(1);\n"
18083 "function foo() {\n"
18087 "var x;eval('new foo();');";
18088 v8::Handle<v8::String> overview_src =
18089 v8::String::NewFromUtf8(isolate, overview_source);
18090 v8::ScriptCompiler::Source script_source(overview_src,
18091 v8::ScriptOrigin(origin));
18092 v8::Handle<Value> overview_result(
18093 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
18094 ->BindToCurrentContext()
18096 CHECK(!overview_result.IsEmpty());
18097 CHECK(overview_result->IsObject());
18099 // Test getting DETAILED information.
18100 const char *detailed_source =
18101 "function bat() {AnalyzeStackInNativeCode(2);\n"
18104 "function baz() {\n"
18107 "eval('new baz();');";
18108 v8::Handle<v8::String> detailed_src =
18109 v8::String::NewFromUtf8(isolate, detailed_source);
18110 // Make the script using a non-zero line and column offset.
18111 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
18112 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
18113 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
18114 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
18115 v8::Handle<v8::UnboundScript> detailed_script(
18116 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
18117 v8::Handle<Value> detailed_result(
18118 detailed_script->BindToCurrentContext()->Run());
18119 CHECK(!detailed_result.IsEmpty());
18120 CHECK(detailed_result->IsObject());
18124 static void StackTraceForUncaughtExceptionListener(
18125 v8::Handle<v8::Message> message,
18126 v8::Handle<Value>) {
18128 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18129 CHECK_EQ(2, stack_trace->GetFrameCount());
18130 checkStackFrame("origin", "foo", 2, 3, false, false,
18131 stack_trace->GetFrame(0));
18132 checkStackFrame("origin", "bar", 5, 3, false, false,
18133 stack_trace->GetFrame(1));
18137 TEST(CaptureStackTraceForUncaughtException) {
18140 v8::HandleScope scope(env->GetIsolate());
18141 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
18142 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18144 CompileRunWithOrigin(
18145 "function foo() {\n"
18148 "function bar() {\n"
18152 v8::Local<v8::Object> global = env->Global();
18153 Local<Value> trouble = global->Get(v8_str("bar"));
18154 CHECK(trouble->IsFunction());
18155 Function::Cast(*trouble)->Call(global, 0, NULL);
18156 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18157 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
18158 CHECK_EQ(1, report_count);
18162 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
18165 v8::HandleScope scope(env->GetIsolate());
18167 // Create an Error object first.
18168 CompileRunWithOrigin(
18169 "function foo() {\n"
18170 "e=new Error('err');\n"
18172 "function bar() {\n"
18177 v8::Local<v8::Object> global = env->Global();
18178 Local<Value> trouble = global->Get(v8_str("bar"));
18179 CHECK(trouble->IsFunction());
18180 Function::Cast(*trouble)->Call(global, 0, NULL);
18182 // Enable capturing detailed stack trace late, and throw the exception.
18183 // The detailed stack trace should be extracted from the simple stack.
18184 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
18185 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18186 CompileRunWithOrigin("throw e", "origin");
18187 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18188 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
18189 CHECK_EQ(1, report_count);
18193 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
18195 v8::HandleScope scope(env->GetIsolate());
18196 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
18198 v8::StackTrace::kDetailed);
18201 "var setters = ['column', 'lineNumber', 'scriptName',\n"
18202 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
18203 " 'isConstructor'];\n"
18204 "for (var i = 0; i < setters.length; i++) {\n"
18205 " var prop = setters[i];\n"
18206 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
18208 CompileRun("throw 'exception';");
18209 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18213 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
18214 v8::Handle<v8::Value> data) {
18215 // Use the frame where JavaScript is called from.
18216 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18217 CHECK(!stack_trace.IsEmpty());
18218 int frame_count = stack_trace->GetFrameCount();
18219 CHECK_EQ(3, frame_count);
18220 int line_number[] = {1, 2, 5};
18221 for (int i = 0; i < frame_count; i++) {
18222 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
18227 // Test that we only return the stack trace at the site where the exception
18228 // is first thrown (not where it is rethrown).
18229 TEST(RethrowStackTrace) {
18231 v8::HandleScope scope(env->GetIsolate());
18232 // We make sure that
18233 // - the stack trace of the ReferenceError in g() is reported.
18234 // - the stack trace is not overwritten when e1 is rethrown by t().
18235 // - the stack trace of e2 does not overwrite that of e1.
18236 const char* source =
18237 "function g() { error; } \n"
18238 "function f() { g(); } \n"
18239 "function t(e) { throw e; } \n"
18242 "} catch (e1) { \n"
18245 " } catch (e2) { \n"
18249 v8::V8::AddMessageListener(RethrowStackTraceHandler);
18250 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18251 CompileRun(source);
18252 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18253 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
18257 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
18258 v8::Handle<v8::Value> data) {
18259 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18260 CHECK(!stack_trace.IsEmpty());
18261 int frame_count = stack_trace->GetFrameCount();
18262 CHECK_EQ(2, frame_count);
18263 int line_number[] = {3, 7};
18264 for (int i = 0; i < frame_count; i++) {
18265 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
18270 // Test that we do not recognize identity for primitive exceptions.
18271 TEST(RethrowPrimitiveStackTrace) {
18273 v8::HandleScope scope(env->GetIsolate());
18274 // We do not capture stack trace for non Error objects on creation time.
18275 // Instead, we capture the stack trace on last throw.
18276 const char* source =
18277 "function g() { throw 404; } \n"
18278 "function f() { g(); } \n"
18279 "function t(e) { throw e; } \n"
18282 "} catch (e1) { \n"
18285 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
18286 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18287 CompileRun(source);
18288 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18289 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
18293 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
18294 v8::Handle<v8::Value> data) {
18295 // Use the frame where JavaScript is called from.
18296 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18297 CHECK(!stack_trace.IsEmpty());
18298 CHECK_EQ(1, stack_trace->GetFrameCount());
18299 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
18303 // Test that the stack trace is captured when the error object is created and
18304 // not where it is thrown.
18305 TEST(RethrowExistingStackTrace) {
18307 v8::HandleScope scope(env->GetIsolate());
18308 const char* source =
18309 "var e = new Error(); \n"
18311 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
18312 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18313 CompileRun(source);
18314 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18315 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
18319 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
18320 v8::Handle<v8::Value> data) {
18321 // Use the frame where JavaScript is called from.
18322 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
18323 CHECK(!stack_trace.IsEmpty());
18324 CHECK_EQ(1, stack_trace->GetFrameCount());
18325 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
18329 // Test that the stack trace is captured where the bogus Error object is thrown.
18330 TEST(RethrowBogusErrorStackTrace) {
18332 v8::HandleScope scope(env->GetIsolate());
18333 const char* source =
18334 "var e = {__proto__: new Error()} \n"
18336 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
18337 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
18338 CompileRun(source);
18339 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
18340 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
18344 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
18345 int promise_reject_counter = 0;
18346 int promise_revoke_counter = 0;
18347 int promise_reject_line_number = -1;
18348 int promise_reject_frame_count = -1;
18350 void PromiseRejectCallback(v8::PromiseRejectMessage message) {
18351 if (message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
18352 promise_reject_counter++;
18353 CcTest::global()->Set(v8_str("rejected"), message.GetPromise());
18354 CcTest::global()->Set(v8_str("value"), message.GetValue());
18355 v8::Handle<v8::StackTrace> stack_trace =
18356 v8::Exception::CreateMessage(message.GetValue())->GetStackTrace();
18357 if (!stack_trace.IsEmpty()) {
18358 promise_reject_frame_count = stack_trace->GetFrameCount();
18359 if (promise_reject_frame_count > 0) {
18360 CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
18361 promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
18363 promise_reject_line_number = -1;
18367 promise_revoke_counter++;
18368 CcTest::global()->Set(v8_str("revoked"), message.GetPromise());
18369 CHECK(message.GetValue().IsEmpty());
18374 v8::Handle<v8::Promise> GetPromise(const char* name) {
18375 return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
18379 v8::Handle<v8::Value> RejectValue() {
18380 return CcTest::global()->Get(v8_str("value"));
18384 void ResetPromiseStates() {
18385 promise_reject_counter = 0;
18386 promise_revoke_counter = 0;
18387 promise_reject_line_number = -1;
18388 promise_reject_frame_count = -1;
18389 CcTest::global()->Set(v8_str("rejected"), v8_str(""));
18390 CcTest::global()->Set(v8_str("value"), v8_str(""));
18391 CcTest::global()->Set(v8_str("revoked"), v8_str(""));
18395 TEST(PromiseRejectCallback) {
18397 v8::Isolate* isolate = env->GetIsolate();
18398 v8::HandleScope scope(isolate);
18400 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
18402 ResetPromiseStates();
18404 // Create promise p0.
18407 "var p0 = new Promise( \n"
18408 " function(res, rej) { \n"
18409 " reject = rej; \n"
18412 CHECK(!GetPromise("p0")->HasHandler());
18413 CHECK_EQ(0, promise_reject_counter);
18414 CHECK_EQ(0, promise_revoke_counter);
18416 // Add resolve handler (and default reject handler) to p0.
18417 CompileRun("var p1 = p0.then(function(){});");
18418 CHECK(GetPromise("p0")->HasHandler());
18419 CHECK(!GetPromise("p1")->HasHandler());
18420 CHECK_EQ(0, promise_reject_counter);
18421 CHECK_EQ(0, promise_revoke_counter);
18424 CompileRun("reject('ppp');");
18425 CHECK(GetPromise("p0")->HasHandler());
18426 CHECK(!GetPromise("p1")->HasHandler());
18427 CHECK_EQ(1, promise_reject_counter);
18428 CHECK_EQ(0, promise_revoke_counter);
18429 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
18430 CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
18431 CHECK(RejectValue()->Equals(v8_str("ppp")));
18433 // Reject p0 again. Callback is not triggered again.
18434 CompileRun("reject();");
18435 CHECK(GetPromise("p0")->HasHandler());
18436 CHECK(!GetPromise("p1")->HasHandler());
18437 CHECK_EQ(1, promise_reject_counter);
18438 CHECK_EQ(0, promise_revoke_counter);
18440 // Add resolve handler to p1.
18441 CompileRun("var p2 = p1.then(function(){});");
18442 CHECK(GetPromise("p0")->HasHandler());
18443 CHECK(GetPromise("p1")->HasHandler());
18444 CHECK(!GetPromise("p2")->HasHandler());
18445 CHECK_EQ(2, promise_reject_counter);
18446 CHECK_EQ(1, promise_revoke_counter);
18447 CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
18448 CHECK(RejectValue()->Equals(v8_str("ppp")));
18449 CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
18451 ResetPromiseStates();
18453 // Create promise q0.
18455 "var q0 = new Promise( \n"
18456 " function(res, rej) { \n"
18457 " reject = rej; \n"
18460 CHECK(!GetPromise("q0")->HasHandler());
18461 CHECK_EQ(0, promise_reject_counter);
18462 CHECK_EQ(0, promise_revoke_counter);
18464 // Add reject handler to q0.
18465 CompileRun("var q1 = q0.catch(function() {});");
18466 CHECK(GetPromise("q0")->HasHandler());
18467 CHECK(!GetPromise("q1")->HasHandler());
18468 CHECK_EQ(0, promise_reject_counter);
18469 CHECK_EQ(0, promise_revoke_counter);
18472 CompileRun("reject('qq')");
18473 CHECK(GetPromise("q0")->HasHandler());
18474 CHECK(!GetPromise("q1")->HasHandler());
18475 CHECK_EQ(0, promise_reject_counter);
18476 CHECK_EQ(0, promise_revoke_counter);
18478 // Add a new reject handler, which rejects by returning Promise.reject().
18479 // The returned promise q_ triggers a reject callback at first, only to
18480 // revoke it when returning it causes q2 to be rejected.
18483 "var q2 = q0.catch( \n"
18485 " q_ = Promise.reject('qqq'); \n"
18489 CHECK(GetPromise("q0")->HasHandler());
18490 CHECK(!GetPromise("q1")->HasHandler());
18491 CHECK(!GetPromise("q2")->HasHandler());
18492 CHECK(GetPromise("q_")->HasHandler());
18493 CHECK_EQ(2, promise_reject_counter);
18494 CHECK_EQ(1, promise_revoke_counter);
18495 CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
18496 CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
18497 CHECK(RejectValue()->Equals(v8_str("qqq")));
18499 // Add a reject handler to the resolved q1, which rejects by throwing.
18501 "var q3 = q1.then( \n"
18503 " throw 'qqqq'; \n"
18506 CHECK(GetPromise("q0")->HasHandler());
18507 CHECK(GetPromise("q1")->HasHandler());
18508 CHECK(!GetPromise("q2")->HasHandler());
18509 CHECK(!GetPromise("q3")->HasHandler());
18510 CHECK_EQ(3, promise_reject_counter);
18511 CHECK_EQ(1, promise_revoke_counter);
18512 CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
18513 CHECK(RejectValue()->Equals(v8_str("qqqq")));
18515 ResetPromiseStates();
18517 // Create promise r0, which has three handlers, two of which handle rejects.
18519 "var r0 = new Promise( \n"
18520 " function(res, rej) { \n"
18521 " reject = rej; \n"
18524 "var r1 = r0.catch(function() {}); \n"
18525 "var r2 = r0.then(function() {}); \n"
18526 "var r3 = r0.then(function() {}, \n"
18527 " function() {}); \n");
18528 CHECK(GetPromise("r0")->HasHandler());
18529 CHECK(!GetPromise("r1")->HasHandler());
18530 CHECK(!GetPromise("r2")->HasHandler());
18531 CHECK(!GetPromise("r3")->HasHandler());
18532 CHECK_EQ(0, promise_reject_counter);
18533 CHECK_EQ(0, promise_revoke_counter);
18536 CompileRun("reject('rrr')");
18537 CHECK(GetPromise("r0")->HasHandler());
18538 CHECK(!GetPromise("r1")->HasHandler());
18539 CHECK(!GetPromise("r2")->HasHandler());
18540 CHECK(!GetPromise("r3")->HasHandler());
18541 CHECK_EQ(1, promise_reject_counter);
18542 CHECK_EQ(0, promise_revoke_counter);
18543 CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
18544 CHECK(RejectValue()->Equals(v8_str("rrr")));
18546 // Add reject handler to r2.
18547 CompileRun("var r4 = r2.catch(function() {});");
18548 CHECK(GetPromise("r0")->HasHandler());
18549 CHECK(!GetPromise("r1")->HasHandler());
18550 CHECK(GetPromise("r2")->HasHandler());
18551 CHECK(!GetPromise("r3")->HasHandler());
18552 CHECK(!GetPromise("r4")->HasHandler());
18553 CHECK_EQ(1, promise_reject_counter);
18554 CHECK_EQ(1, promise_revoke_counter);
18555 CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
18556 CHECK(RejectValue()->Equals(v8_str("rrr")));
18558 // Add reject handlers to r4.
18559 CompileRun("var r5 = r4.then(function() {}, function() {});");
18560 CHECK(GetPromise("r0")->HasHandler());
18561 CHECK(!GetPromise("r1")->HasHandler());
18562 CHECK(GetPromise("r2")->HasHandler());
18563 CHECK(!GetPromise("r3")->HasHandler());
18564 CHECK(GetPromise("r4")->HasHandler());
18565 CHECK(!GetPromise("r5")->HasHandler());
18566 CHECK_EQ(1, promise_reject_counter);
18567 CHECK_EQ(1, promise_revoke_counter);
18569 ResetPromiseStates();
18571 // Create promise s0, which has three handlers, none of which handle rejects.
18573 "var s0 = new Promise( \n"
18574 " function(res, rej) { \n"
18575 " reject = rej; \n"
18578 "var s1 = s0.then(function() {}); \n"
18579 "var s2 = s0.then(function() {}); \n"
18580 "var s3 = s0.then(function() {}); \n");
18581 CHECK(GetPromise("s0")->HasHandler());
18582 CHECK(!GetPromise("s1")->HasHandler());
18583 CHECK(!GetPromise("s2")->HasHandler());
18584 CHECK(!GetPromise("s3")->HasHandler());
18585 CHECK_EQ(0, promise_reject_counter);
18586 CHECK_EQ(0, promise_revoke_counter);
18589 CompileRun("reject('sss')");
18590 CHECK(GetPromise("s0")->HasHandler());
18591 CHECK(!GetPromise("s1")->HasHandler());
18592 CHECK(!GetPromise("s2")->HasHandler());
18593 CHECK(!GetPromise("s3")->HasHandler());
18594 CHECK_EQ(3, promise_reject_counter);
18595 CHECK_EQ(0, promise_revoke_counter);
18596 CHECK(RejectValue()->Equals(v8_str("sss")));
18598 // Test stack frames.
18599 V8::SetCaptureStackTraceForUncaughtExceptions(true);
18601 ResetPromiseStates();
18603 // Create promise t0, which is rejected in the constructor with an error.
18604 CompileRunWithOrigin(
18605 "var t0 = new Promise( \n"
18606 " function(res, rej) { \n"
18607 " reference_error; \n"
18611 CHECK(!GetPromise("t0")->HasHandler());
18612 CHECK_EQ(1, promise_reject_counter);
18613 CHECK_EQ(0, promise_revoke_counter);
18614 CHECK_EQ(2, promise_reject_frame_count);
18615 CHECK_EQ(3, promise_reject_line_number);
18617 ResetPromiseStates();
18619 // Create promise u0 and chain u1 to it, which is rejected via throw.
18620 CompileRunWithOrigin(
18621 "var u0 = Promise.resolve(); \n"
18622 "var u1 = u0.then( \n"
18624 " (function() { \n"
18625 " throw new Error(); \n"
18630 CHECK(GetPromise("u0")->HasHandler());
18631 CHECK(!GetPromise("u1")->HasHandler());
18632 CHECK_EQ(1, promise_reject_counter);
18633 CHECK_EQ(0, promise_revoke_counter);
18634 CHECK_EQ(2, promise_reject_frame_count);
18635 CHECK_EQ(5, promise_reject_line_number);
18637 // Throw in u3, which handles u1's rejection.
18638 CompileRunWithOrigin(
18639 "function f() { \n"
18640 " return (function() { \n"
18641 " return new Error(); \n"
18644 "var u2 = Promise.reject(f()); \n"
18645 "var u3 = u1.catch( \n"
18651 CHECK(GetPromise("u0")->HasHandler());
18652 CHECK(GetPromise("u1")->HasHandler());
18653 CHECK(GetPromise("u2")->HasHandler());
18654 CHECK(!GetPromise("u3")->HasHandler());
18655 CHECK_EQ(3, promise_reject_counter);
18656 CHECK_EQ(2, promise_revoke_counter);
18657 CHECK_EQ(3, promise_reject_frame_count);
18658 CHECK_EQ(3, promise_reject_line_number);
18660 ResetPromiseStates();
18662 // Create promise rejected promise v0, which is incorrectly handled by v1
18663 // via chaining cycle.
18664 CompileRunWithOrigin(
18665 "var v0 = Promise.reject(); \n"
18666 "var v1 = v0.catch( \n"
18672 CHECK(GetPromise("v0")->HasHandler());
18673 CHECK(!GetPromise("v1")->HasHandler());
18674 CHECK_EQ(2, promise_reject_counter);
18675 CHECK_EQ(1, promise_revoke_counter);
18676 CHECK_EQ(0, promise_reject_frame_count);
18677 CHECK_EQ(-1, promise_reject_line_number);
18681 void AnalyzeStackOfEvalWithSourceURL(
18682 const v8::FunctionCallbackInfo<v8::Value>& args) {
18683 v8::HandleScope scope(args.GetIsolate());
18684 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18685 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18686 CHECK_EQ(5, stackTrace->GetFrameCount());
18687 v8::Handle<v8::String> url = v8_str("eval_url");
18688 for (int i = 0; i < 3; i++) {
18689 v8::Handle<v8::String> name =
18690 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18691 CHECK(!name.IsEmpty());
18692 CHECK_EQ(url, name);
18697 TEST(SourceURLInStackTrace) {
18698 v8::Isolate* isolate = CcTest::isolate();
18699 v8::HandleScope scope(isolate);
18700 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18701 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
18702 v8::FunctionTemplate::New(isolate,
18703 AnalyzeStackOfEvalWithSourceURL));
18704 LocalContext context(0, templ);
18706 const char *source =
18707 "function outer() {\n"
18708 "function bar() {\n"
18709 " AnalyzeStackOfEvalWithSourceURL();\n"
18711 "function foo() {\n"
18717 "eval('(' + outer +')()%s');";
18719 i::ScopedVector<char> code(1024);
18720 i::SNPrintF(code, source, "//# sourceURL=eval_url");
18721 CHECK(CompileRun(code.start())->IsUndefined());
18722 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
18723 CHECK(CompileRun(code.start())->IsUndefined());
18727 static int scriptIdInStack[2];
18729 void AnalyzeScriptIdInStack(
18730 const v8::FunctionCallbackInfo<v8::Value>& args) {
18731 v8::HandleScope scope(args.GetIsolate());
18732 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18733 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
18734 CHECK_EQ(2, stackTrace->GetFrameCount());
18735 for (int i = 0; i < 2; i++) {
18736 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
18741 TEST(ScriptIdInStackTrace) {
18742 v8::Isolate* isolate = CcTest::isolate();
18743 v8::HandleScope scope(isolate);
18744 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18745 templ->Set(v8_str("AnalyzeScriptIdInStack"),
18746 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
18747 LocalContext context(0, templ);
18749 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18751 "function foo() {\n"
18752 " AnalyzeScriptIdInStack();"
18755 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
18757 for (int i = 0; i < 2; i++) {
18758 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
18759 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
18764 void AnalyzeStackOfInlineScriptWithSourceURL(
18765 const v8::FunctionCallbackInfo<v8::Value>& args) {
18766 v8::HandleScope scope(args.GetIsolate());
18767 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18768 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18769 CHECK_EQ(4, stackTrace->GetFrameCount());
18770 v8::Handle<v8::String> url = v8_str("url");
18771 for (int i = 0; i < 3; i++) {
18772 v8::Handle<v8::String> name =
18773 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18774 CHECK(!name.IsEmpty());
18775 CHECK_EQ(url, name);
18780 TEST(InlineScriptWithSourceURLInStackTrace) {
18781 v8::Isolate* isolate = CcTest::isolate();
18782 v8::HandleScope scope(isolate);
18783 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18784 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
18785 v8::FunctionTemplate::New(
18786 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
18787 LocalContext context(0, templ);
18789 const char *source =
18790 "function outer() {\n"
18791 "function bar() {\n"
18792 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
18794 "function foo() {\n"
18802 i::ScopedVector<char> code(1024);
18803 i::SNPrintF(code, source, "//# sourceURL=source_url");
18804 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18805 i::SNPrintF(code, source, "//@ sourceURL=source_url");
18806 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18810 void AnalyzeStackOfDynamicScriptWithSourceURL(
18811 const v8::FunctionCallbackInfo<v8::Value>& args) {
18812 v8::HandleScope scope(args.GetIsolate());
18813 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18814 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18815 CHECK_EQ(4, stackTrace->GetFrameCount());
18816 v8::Handle<v8::String> url = v8_str("source_url");
18817 for (int i = 0; i < 3; i++) {
18818 v8::Handle<v8::String> name =
18819 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18820 CHECK(!name.IsEmpty());
18821 CHECK_EQ(url, name);
18826 TEST(DynamicWithSourceURLInStackTrace) {
18827 v8::Isolate* isolate = CcTest::isolate();
18828 v8::HandleScope scope(isolate);
18829 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18830 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
18831 v8::FunctionTemplate::New(
18832 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
18833 LocalContext context(0, templ);
18835 const char *source =
18836 "function outer() {\n"
18837 "function bar() {\n"
18838 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
18840 "function foo() {\n"
18848 i::ScopedVector<char> code(1024);
18849 i::SNPrintF(code, source, "//# sourceURL=source_url");
18850 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18851 i::SNPrintF(code, source, "//@ sourceURL=source_url");
18852 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18856 TEST(DynamicWithSourceURLInStackTraceString) {
18857 LocalContext context;
18858 v8::HandleScope scope(context->GetIsolate());
18860 const char *source =
18861 "function outer() {\n"
18862 " function foo() {\n"
18869 i::ScopedVector<char> code(1024);
18870 i::SNPrintF(code, source, "//# sourceURL=source_url");
18871 v8::TryCatch try_catch;
18872 CompileRunWithOrigin(code.start(), "", 0, 0);
18873 CHECK(try_catch.HasCaught());
18874 v8::String::Utf8Value stack(try_catch.StackTrace());
18875 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
18879 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18880 LocalContext context;
18881 v8::HandleScope scope(context->GetIsolate());
18883 const char *source =
18884 "function outer() {\n"
18885 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
18886 " //# sourceURL=source_url\";\n"
18887 " eval(scriptContents);\n"
18890 "//# sourceURL=outer_url";
18892 v8::TryCatch try_catch;
18893 CompileRun(source);
18894 CHECK(try_catch.HasCaught());
18896 Local<v8::Message> message = try_catch.Message();
18897 Handle<Value> sourceURL =
18898 message->GetScriptOrigin().ResourceName();
18899 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
18903 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18904 LocalContext context;
18905 v8::HandleScope scope(context->GetIsolate());
18907 const char *source =
18908 "function outer() {\n"
18909 " var scriptContents = \"function boo(){ boo(); }\\\n"
18910 " //# sourceURL=source_url\";\n"
18911 " eval(scriptContents);\n"
18914 "//# sourceURL=outer_url";
18916 v8::TryCatch try_catch;
18917 CompileRun(source);
18918 CHECK(try_catch.HasCaught());
18920 Local<v8::Message> message = try_catch.Message();
18921 Handle<Value> sourceURL =
18922 message->GetScriptOrigin().ResourceName();
18923 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
18927 static void CreateGarbageInOldSpace() {
18928 i::Factory* factory = CcTest::i_isolate()->factory();
18929 v8::HandleScope scope(CcTest::isolate());
18930 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
18931 for (int i = 0; i < 1000; i++) {
18932 factory->NewFixedArray(1000, i::TENURED);
18937 // Test that idle notification can be handled and eventually returns true.
18938 TEST(IdleNotification) {
18939 const intptr_t MB = 1024 * 1024;
18940 const int IdlePauseInMs = 1000;
18942 v8::HandleScope scope(env->GetIsolate());
18943 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18944 CreateGarbageInOldSpace();
18945 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18946 CHECK_GT(size_with_garbage, initial_size + MB);
18947 bool finished = false;
18948 for (int i = 0; i < 200 && !finished; i++) {
18949 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18951 intptr_t final_size = CcTest::heap()->SizeOfObjects();
18953 CHECK_LT(final_size, initial_size + 1);
18957 // Test that idle notification can be handled and eventually collects garbage.
18958 TEST(IdleNotificationWithSmallHint) {
18959 const intptr_t MB = 1024 * 1024;
18960 const int IdlePauseInMs = 900;
18962 v8::HandleScope scope(env->GetIsolate());
18963 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18964 CreateGarbageInOldSpace();
18965 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18966 CHECK_GT(size_with_garbage, initial_size + MB);
18967 bool finished = false;
18968 for (int i = 0; i < 200 && !finished; i++) {
18969 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18971 intptr_t final_size = CcTest::heap()->SizeOfObjects();
18973 CHECK_LT(final_size, initial_size + 1);
18977 // Test that idle notification can be handled and eventually collects garbage.
18978 TEST(IdleNotificationWithLargeHint) {
18979 const intptr_t MB = 1024 * 1024;
18980 const int IdlePauseInMs = 900;
18982 v8::HandleScope scope(env->GetIsolate());
18983 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18984 CreateGarbageInOldSpace();
18985 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18986 CHECK_GT(size_with_garbage, initial_size + MB);
18987 bool finished = false;
18988 for (int i = 0; i < 200 && !finished; i++) {
18989 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18991 intptr_t final_size = CcTest::heap()->SizeOfObjects();
18993 CHECK_LT(final_size, initial_size + 1);
18997 TEST(Regress2333) {
18999 for (int i = 0; i < 3; i++) {
19000 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
19004 static uint32_t* stack_limit;
19006 static void GetStackLimitCallback(
19007 const v8::FunctionCallbackInfo<v8::Value>& args) {
19008 stack_limit = reinterpret_cast<uint32_t*>(
19009 CcTest::i_isolate()->stack_guard()->real_climit());
19013 // Uses the address of a local variable to determine the stack top now.
19014 // Given a size, returns an address that is that far from the current
19016 static uint32_t* ComputeStackLimit(uint32_t size) {
19017 uint32_t* answer = &size - (size / sizeof(size));
19018 // If the size is very large and the stack is very near the bottom of
19019 // memory then the calculation above may wrap around and give an address
19020 // that is above the (downwards-growing) stack. In that case we return
19021 // a very low address.
19022 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
19027 // We need at least 165kB for an x64 debug build with clang and ASAN.
19028 static const int stack_breathing_room = 256 * i::KB;
19031 TEST(SetStackLimit) {
19032 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
19034 // Set stack limit.
19035 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
19037 // Execute a script.
19039 v8::HandleScope scope(env->GetIsolate());
19040 Local<v8::FunctionTemplate> fun_templ =
19041 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
19042 Local<Function> fun = fun_templ->GetFunction();
19043 env->Global()->Set(v8_str("get_stack_limit"), fun);
19044 CompileRun("get_stack_limit();");
19046 CHECK(stack_limit == set_limit);
19050 TEST(SetStackLimitInThread) {
19051 uint32_t* set_limit;
19053 v8::Locker locker(CcTest::isolate());
19054 set_limit = ComputeStackLimit(stack_breathing_room);
19056 // Set stack limit.
19057 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
19059 // Execute a script.
19060 v8::HandleScope scope(CcTest::isolate());
19062 Local<v8::FunctionTemplate> fun_templ =
19063 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
19064 Local<Function> fun = fun_templ->GetFunction();
19065 env->Global()->Set(v8_str("get_stack_limit"), fun);
19066 CompileRun("get_stack_limit();");
19068 CHECK(stack_limit == set_limit);
19071 v8::Locker locker(CcTest::isolate());
19072 CHECK(stack_limit == set_limit);
19077 THREADED_TEST(GetHeapStatistics) {
19079 v8::HandleScope scope(c1->GetIsolate());
19080 v8::HeapStatistics heap_statistics;
19081 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
19082 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
19083 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
19084 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
19085 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
19089 class VisitorImpl : public v8::ExternalResourceVisitor {
19091 explicit VisitorImpl(TestResource** resource) {
19092 for (int i = 0; i < 4; i++) {
19093 resource_[i] = resource[i];
19094 found_resource_[i] = false;
19097 virtual ~VisitorImpl() {}
19098 virtual void VisitExternalString(v8::Handle<v8::String> string) {
19099 if (!string->IsExternal()) {
19100 CHECK(string->IsExternalOneByte());
19103 v8::String::ExternalStringResource* resource =
19104 string->GetExternalStringResource();
19106 for (int i = 0; i < 4; i++) {
19107 if (resource_[i] == resource) {
19108 CHECK(!found_resource_[i]);
19109 found_resource_[i] = true;
19113 void CheckVisitedResources() {
19114 for (int i = 0; i < 4; i++) {
19115 CHECK(found_resource_[i]);
19120 v8::String::ExternalStringResource* resource_[4];
19121 bool found_resource_[4];
19125 TEST(ExternalizeOldSpaceTwoByteCons) {
19126 v8::Isolate* isolate = CcTest::isolate();
19128 v8::HandleScope scope(isolate);
19129 v8::Local<v8::String> cons =
19130 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
19131 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
19132 CcTest::heap()->CollectAllAvailableGarbage();
19133 CHECK(CcTest::heap()->old_pointer_space()->Contains(
19134 *v8::Utils::OpenHandle(*cons)));
19136 TestResource* resource = new TestResource(
19137 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
19138 cons->MakeExternal(resource);
19140 CHECK(cons->IsExternal());
19141 CHECK_EQ(resource, cons->GetExternalStringResource());
19142 String::Encoding encoding;
19143 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
19144 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
19148 TEST(ExternalizeOldSpaceOneByteCons) {
19149 v8::Isolate* isolate = CcTest::isolate();
19151 v8::HandleScope scope(isolate);
19152 v8::Local<v8::String> cons =
19153 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
19154 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
19155 CcTest::heap()->CollectAllAvailableGarbage();
19156 CHECK(CcTest::heap()->old_pointer_space()->Contains(
19157 *v8::Utils::OpenHandle(*cons)));
19159 TestOneByteResource* resource =
19160 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
19161 cons->MakeExternal(resource);
19163 CHECK(cons->IsExternalOneByte());
19164 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
19165 String::Encoding encoding;
19166 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
19167 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
19171 TEST(VisitExternalStrings) {
19172 v8::Isolate* isolate = CcTest::isolate();
19174 v8::HandleScope scope(isolate);
19175 const char* string = "Some string";
19176 uint16_t* two_byte_string = AsciiToTwoByteString(string);
19177 TestResource* resource[4];
19178 resource[0] = new TestResource(two_byte_string);
19179 v8::Local<v8::String> string0 =
19180 v8::String::NewExternal(env->GetIsolate(), resource[0]);
19181 resource[1] = new TestResource(two_byte_string, NULL, false);
19182 v8::Local<v8::String> string1 =
19183 v8::String::NewExternal(env->GetIsolate(), resource[1]);
19185 // Externalized symbol.
19186 resource[2] = new TestResource(two_byte_string, NULL, false);
19187 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
19188 env->GetIsolate(), string, v8::String::kInternalizedString);
19189 CHECK(string2->MakeExternal(resource[2]));
19191 // Symbolized External.
19192 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
19193 v8::Local<v8::String> string3 =
19194 v8::String::NewExternal(env->GetIsolate(), resource[3]);
19195 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
19196 // Turn into a symbol.
19197 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
19198 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
19199 string3_i).is_null());
19200 CHECK(string3_i->IsInternalizedString());
19202 // We need to add usages for string* to avoid warnings in GCC 4.7
19203 CHECK(string0->IsExternal());
19204 CHECK(string1->IsExternal());
19205 CHECK(string2->IsExternal());
19206 CHECK(string3->IsExternal());
19208 VisitorImpl visitor(resource);
19209 v8::V8::VisitExternalResources(&visitor);
19210 visitor.CheckVisitedResources();
19214 TEST(ExternalStringCollectedAtTearDown) {
19216 v8::Isolate* isolate = v8::Isolate::New();
19217 { v8::Isolate::Scope isolate_scope(isolate);
19218 v8::HandleScope handle_scope(isolate);
19219 const char* s = "One string to test them all, one string to find them.";
19220 TestOneByteResource* inscription =
19221 new TestOneByteResource(i::StrDup(s), &destroyed);
19222 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
19223 // Ring is still alive. Orcs are roaming freely across our lands.
19224 CHECK_EQ(0, destroyed);
19228 isolate->Dispose();
19229 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
19230 CHECK_EQ(1, destroyed);
19234 TEST(ExternalInternalizedStringCollectedAtTearDown) {
19236 v8::Isolate* isolate = v8::Isolate::New();
19237 { v8::Isolate::Scope isolate_scope(isolate);
19238 LocalContext env(isolate);
19239 v8::HandleScope handle_scope(isolate);
19240 CompileRun("var ring = 'One string to test them all';");
19241 const char* s = "One string to test them all";
19242 TestOneByteResource* inscription =
19243 new TestOneByteResource(i::StrDup(s), &destroyed);
19244 v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
19245 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
19246 ring->MakeExternal(inscription);
19247 // Ring is still alive. Orcs are roaming freely across our lands.
19248 CHECK_EQ(0, destroyed);
19252 isolate->Dispose();
19253 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
19254 CHECK_EQ(1, destroyed);
19258 TEST(ExternalInternalizedStringCollectedAtGC) {
19259 // TODO(mvstanton): vector ics need weak support.
19260 if (i::FLAG_vector_ics) return;
19263 { LocalContext env;
19264 v8::HandleScope handle_scope(env->GetIsolate());
19265 CompileRun("var ring = 'One string to test them all';");
19266 const char* s = "One string to test them all";
19267 TestOneByteResource* inscription =
19268 new TestOneByteResource(i::StrDup(s), &destroyed);
19269 v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
19270 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
19271 ring->MakeExternal(inscription);
19272 // Ring is still alive. Orcs are roaming freely across our lands.
19273 CHECK_EQ(0, destroyed);
19277 // Garbage collector deals swift blows to evil.
19278 CcTest::i_isolate()->compilation_cache()->Clear();
19279 CcTest::heap()->CollectAllAvailableGarbage();
19281 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
19282 CHECK_EQ(1, destroyed);
19286 static double DoubleFromBits(uint64_t value) {
19288 i::MemCopy(&target, &value, sizeof(target));
19293 static uint64_t DoubleToBits(double value) {
19295 i::MemCopy(&target, &value, sizeof(target));
19300 static double DoubleToDateTime(double input) {
19301 double date_limit = 864e13;
19302 if (std::isnan(input) || input < -date_limit || input > date_limit) {
19303 return v8::base::OS::nan_value();
19305 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
19309 // We don't have a consistent way to write 64-bit constants syntactically, so we
19310 // split them into two 32-bit constants and combine them programmatically.
19311 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
19312 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
19316 THREADED_TEST(QuietSignalingNaNs) {
19317 LocalContext context;
19318 v8::Isolate* isolate = context->GetIsolate();
19319 v8::HandleScope scope(isolate);
19320 v8::TryCatch try_catch;
19322 // Special double values.
19323 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
19324 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
19325 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
19326 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
19327 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
19328 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
19329 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
19331 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
19332 // on either side of the epoch.
19333 double date_limit = 864e13;
19335 double test_values[] = {
19357 int num_test_values = 20;
19359 for (int i = 0; i < num_test_values; i++) {
19360 double test_value = test_values[i];
19362 // Check that Number::New preserves non-NaNs and quiets SNaNs.
19363 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
19364 double stored_number = number->NumberValue();
19365 if (!std::isnan(test_value)) {
19366 CHECK_EQ(test_value, stored_number);
19368 uint64_t stored_bits = DoubleToBits(stored_number);
19369 // Check if quiet nan (bits 51..62 all set).
19370 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19371 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
19372 // Most significant fraction bit for quiet nan is set to 0
19373 // on MIPS architecture. Allowed by IEEE-754.
19374 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19376 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
19380 // Check that Date::New preserves non-NaNs in the date range and
19382 v8::Handle<v8::Value> date =
19383 v8::Date::New(isolate, test_value);
19384 double expected_stored_date = DoubleToDateTime(test_value);
19385 double stored_date = date->NumberValue();
19386 if (!std::isnan(expected_stored_date)) {
19387 CHECK_EQ(expected_stored_date, stored_date);
19389 uint64_t stored_bits = DoubleToBits(stored_date);
19390 // Check if quiet nan (bits 51..62 all set).
19391 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19392 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
19393 // Most significant fraction bit for quiet nan is set to 0
19394 // on MIPS architecture. Allowed by IEEE-754.
19395 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19397 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
19404 static void SpaghettiIncident(
19405 const v8::FunctionCallbackInfo<v8::Value>& args) {
19406 v8::HandleScope scope(args.GetIsolate());
19408 v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
19410 if (tc.HasCaught())
19415 // Test that an exception can be propagated down through a spaghetti
19416 // stack using ReThrow.
19417 THREADED_TEST(SpaghettiStackReThrow) {
19418 v8::Isolate* isolate = CcTest::isolate();
19419 v8::HandleScope scope(isolate);
19420 LocalContext context;
19421 context->Global()->Set(
19422 v8::String::NewFromUtf8(isolate, "s"),
19423 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
19424 v8::TryCatch try_catch;
19428 " toString: function () {"
19438 CHECK(try_catch.HasCaught());
19439 v8::String::Utf8Value value(try_catch.Exception());
19440 CHECK_EQ(0, strcmp(*value, "Hey!"));
19445 v8::V8::Initialize();
19446 v8::Isolate* isolate = CcTest::isolate();
19447 v8::HandleScope scope(isolate);
19448 v8::Local<Context> other_context;
19451 // Create a context used to keep the code from aging in the compilation
19453 other_context = Context::New(isolate);
19455 // Context-dependent context data creates reference from the compilation
19456 // cache to the global object.
19457 const char* source_simple = "1";
19459 v8::HandleScope scope(isolate);
19460 v8::Local<Context> context = Context::New(isolate);
19463 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
19464 context->SetEmbedderData(0, obj);
19465 CompileRun(source_simple);
19468 isolate->ContextDisposedNotification();
19469 for (gc_count = 1; gc_count < 10; gc_count++) {
19470 other_context->Enter();
19471 CompileRun(source_simple);
19472 other_context->Exit();
19473 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19474 if (GetGlobalObjectsCount() == 1) break;
19476 CHECK_GE(2, gc_count);
19477 CHECK_EQ(1, GetGlobalObjectsCount());
19479 // Eval in a function creates reference from the compilation cache to the
19481 const char* source_eval = "function f(){eval('1')}; f()";
19483 v8::HandleScope scope(isolate);
19484 v8::Local<Context> context = Context::New(isolate);
19487 CompileRun(source_eval);
19490 isolate->ContextDisposedNotification();
19491 for (gc_count = 1; gc_count < 10; gc_count++) {
19492 other_context->Enter();
19493 CompileRun(source_eval);
19494 other_context->Exit();
19495 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19496 if (GetGlobalObjectsCount() == 1) break;
19498 CHECK_GE(2, gc_count);
19499 CHECK_EQ(1, GetGlobalObjectsCount());
19501 // Looking up the line number for an exception creates reference from the
19502 // compilation cache to the global object.
19503 const char* source_exception = "function f(){throw 1;} f()";
19505 v8::HandleScope scope(isolate);
19506 v8::Local<Context> context = Context::New(isolate);
19509 v8::TryCatch try_catch;
19510 CompileRun(source_exception);
19511 CHECK(try_catch.HasCaught());
19512 v8::Handle<v8::Message> message = try_catch.Message();
19513 CHECK(!message.IsEmpty());
19514 CHECK_EQ(1, message->GetLineNumber());
19517 isolate->ContextDisposedNotification();
19518 for (gc_count = 1; gc_count < 10; gc_count++) {
19519 other_context->Enter();
19520 CompileRun(source_exception);
19521 other_context->Exit();
19522 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19523 if (GetGlobalObjectsCount() == 1) break;
19525 CHECK_GE(2, gc_count);
19526 CHECK_EQ(1, GetGlobalObjectsCount());
19528 isolate->ContextDisposedNotification();
19532 THREADED_TEST(ScriptOrigin) {
19534 v8::HandleScope scope(env->GetIsolate());
19535 v8::ScriptOrigin origin =
19536 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19537 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19538 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
19539 v8::Script::Compile(script, &origin)->Run();
19540 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19541 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19542 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19543 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19545 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
19546 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
19547 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
19549 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
19550 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
19551 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
19555 THREADED_TEST(FunctionGetInferredName) {
19557 v8::HandleScope scope(env->GetIsolate());
19558 v8::ScriptOrigin origin =
19559 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19560 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19562 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
19563 v8::Script::Compile(script, &origin)->Run();
19564 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19565 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19566 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
19570 THREADED_TEST(FunctionGetDisplayName) {
19572 v8::HandleScope scope(env->GetIsolate());
19573 const char* code = "var error = false;"
19574 "function a() { this.x = 1; };"
19575 "a.displayName = 'display_a';"
19576 "var b = (function() {"
19577 " var f = function() { this.x = 2; };"
19578 " f.displayName = 'display_b';"
19581 "var c = function() {};"
19582 "c.__defineGetter__('displayName', function() {"
19584 " throw new Error();"
19587 "d.__defineGetter__('displayName', function() {"
19589 " return 'wrong_display_name';"
19592 "e.displayName = 'wrong_display_name';"
19593 "e.__defineSetter__('displayName', function() {"
19595 " throw new Error();"
19598 "f.displayName = { 'foo': 6, toString: function() {"
19600 " return 'wrong_display_name';"
19602 "var g = function() {"
19603 " arguments.callee.displayName = 'set_in_runtime';"
19606 v8::ScriptOrigin origin =
19607 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19608 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
19610 v8::Local<v8::Value> error =
19611 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
19612 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
19613 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
19614 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
19615 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
19616 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
19617 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
19618 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
19619 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
19620 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
19621 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
19622 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19623 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19624 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19625 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19626 CHECK_EQ(false, error->BooleanValue());
19627 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
19628 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
19629 CHECK(c->GetDisplayName()->IsUndefined());
19630 CHECK(d->GetDisplayName()->IsUndefined());
19631 CHECK(e->GetDisplayName()->IsUndefined());
19632 CHECK(f->GetDisplayName()->IsUndefined());
19633 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
19637 THREADED_TEST(ScriptLineNumber) {
19639 v8::HandleScope scope(env->GetIsolate());
19640 v8::ScriptOrigin origin =
19641 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19642 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19643 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
19644 v8::Script::Compile(script, &origin)->Run();
19645 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19646 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19647 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19648 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19649 CHECK_EQ(0, f->GetScriptLineNumber());
19650 CHECK_EQ(2, g->GetScriptLineNumber());
19654 THREADED_TEST(ScriptColumnNumber) {
19656 v8::Isolate* isolate = env->GetIsolate();
19657 v8::HandleScope scope(isolate);
19658 v8::ScriptOrigin origin =
19659 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
19660 v8::Integer::New(isolate, 3),
19661 v8::Integer::New(isolate, 2));
19662 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19663 isolate, "function foo() {}\n\n function bar() {}");
19664 v8::Script::Compile(script, &origin)->Run();
19665 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19666 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
19667 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19668 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
19669 CHECK_EQ(14, foo->GetScriptColumnNumber());
19670 CHECK_EQ(17, bar->GetScriptColumnNumber());
19674 THREADED_TEST(FunctionIsBuiltin) {
19676 v8::Isolate* isolate = env->GetIsolate();
19677 v8::HandleScope scope(isolate);
19678 v8::Local<v8::Function> f;
19679 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
19680 CHECK(f->IsBuiltin());
19681 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
19682 CHECK(f->IsBuiltin());
19683 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
19684 CHECK(f->IsBuiltin());
19685 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
19686 CHECK(f->IsBuiltin());
19687 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
19688 CHECK(!f->IsBuiltin());
19692 THREADED_TEST(FunctionGetScriptId) {
19694 v8::Isolate* isolate = env->GetIsolate();
19695 v8::HandleScope scope(isolate);
19696 v8::ScriptOrigin origin =
19697 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
19698 v8::Integer::New(isolate, 3),
19699 v8::Integer::New(isolate, 2));
19700 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
19701 isolate, "function foo() {}\n\n function bar() {}");
19702 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
19704 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19705 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
19706 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19707 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
19708 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
19709 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
19713 THREADED_TEST(FunctionGetBoundFunction) {
19715 v8::HandleScope scope(env->GetIsolate());
19716 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
19717 env->GetIsolate(), "test"));
19718 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19720 "var a = new Object();\n"
19722 "function f () { return this.x };\n"
19723 "var g = f.bind(a);\n"
19725 v8::Script::Compile(script, &origin)->Run();
19726 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19727 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19728 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19729 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19730 CHECK(g->GetBoundFunction()->IsFunction());
19731 Local<v8::Function> original_function = Local<v8::Function>::Cast(
19732 g->GetBoundFunction());
19733 CHECK_EQ(f->GetName(), original_function->GetName());
19734 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
19735 CHECK_EQ(f->GetScriptColumnNumber(),
19736 original_function->GetScriptColumnNumber());
19740 static void GetterWhichReturns42(
19741 Local<String> name,
19742 const v8::PropertyCallbackInfo<v8::Value>& info) {
19743 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19744 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19745 info.GetReturnValue().Set(v8_num(42));
19749 static void SetterWhichSetsYOnThisTo23(
19750 Local<String> name,
19751 Local<Value> value,
19752 const v8::PropertyCallbackInfo<void>& info) {
19753 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19754 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19755 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19759 void FooGetInterceptor(Local<Name> name,
19760 const v8::PropertyCallbackInfo<v8::Value>& info) {
19761 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19762 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19763 if (!name->Equals(v8_str("foo"))) return;
19764 info.GetReturnValue().Set(v8_num(42));
19768 void FooSetInterceptor(Local<Name> name, Local<Value> value,
19769 const v8::PropertyCallbackInfo<v8::Value>& info) {
19770 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19771 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19772 if (!name->Equals(v8_str("foo"))) return;
19773 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19774 info.GetReturnValue().Set(v8_num(23));
19778 TEST(SetterOnConstructorPrototype) {
19779 v8::Isolate* isolate = CcTest::isolate();
19780 v8::HandleScope scope(isolate);
19781 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19782 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19783 SetterWhichSetsYOnThisTo23);
19784 LocalContext context;
19785 context->Global()->Set(v8_str("P"), templ->NewInstance());
19786 CompileRun("function C1() {"
19789 "C1.prototype = P;"
19793 "C2.prototype = { };"
19794 "C2.prototype.__proto__ = P;");
19796 v8::Local<v8::Script> script;
19797 script = v8_compile("new C1();");
19798 for (int i = 0; i < 10; i++) {
19799 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19800 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
19801 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
19804 script = v8_compile("new C2();");
19805 for (int i = 0; i < 10; i++) {
19806 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
19807 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
19808 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
19813 static void NamedPropertyGetterWhichReturns42(
19814 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
19815 info.GetReturnValue().Set(v8_num(42));
19819 static void NamedPropertySetterWhichSetsYOnThisTo23(
19820 Local<Name> name, Local<Value> value,
19821 const v8::PropertyCallbackInfo<v8::Value>& info) {
19822 if (name->Equals(v8_str("x"))) {
19823 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19828 THREADED_TEST(InterceptorOnConstructorPrototype) {
19829 v8::Isolate* isolate = CcTest::isolate();
19830 v8::HandleScope scope(isolate);
19831 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19832 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
19833 NamedPropertyGetterWhichReturns42,
19834 NamedPropertySetterWhichSetsYOnThisTo23));
19835 LocalContext context;
19836 context->Global()->Set(v8_str("P"), templ->NewInstance());
19837 CompileRun("function C1() {"
19840 "C1.prototype = P;"
19844 "C2.prototype = { };"
19845 "C2.prototype.__proto__ = P;");
19847 v8::Local<v8::Script> script;
19848 script = v8_compile("new C1();");
19849 for (int i = 0; i < 10; i++) {
19850 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19851 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
19852 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
19855 script = v8_compile("new C2();");
19856 for (int i = 0; i < 10; i++) {
19857 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
19858 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
19859 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
19865 const char* source = "function C1() {"
19868 "C1.prototype = P;";
19870 LocalContext context;
19871 v8::Isolate* isolate = context->GetIsolate();
19872 v8::HandleScope scope(isolate);
19873 v8::Local<v8::Script> script;
19875 // Use a simple object as prototype.
19876 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
19877 prototype->Set(v8_str("y"), v8_num(42));
19878 context->Global()->Set(v8_str("P"), prototype);
19880 // This compile will add the code to the compilation cache.
19881 CompileRun(source);
19883 script = v8_compile("new C1();");
19884 // Allow enough iterations for the inobject slack tracking logic
19885 // to finalize instance size and install the fast construct stub.
19886 for (int i = 0; i < 256; i++) {
19887 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19888 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
19889 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
19892 // Use an API object with accessors as prototype.
19893 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19894 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19895 SetterWhichSetsYOnThisTo23);
19896 context->Global()->Set(v8_str("P"), templ->NewInstance());
19898 // This compile will get the code from the compilation cache.
19899 CompileRun(source);
19901 script = v8_compile("new C1();");
19902 for (int i = 0; i < 10; i++) {
19903 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19904 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
19905 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
19909 v8::Isolate* gc_callbacks_isolate = NULL;
19910 int prologue_call_count = 0;
19911 int epilogue_call_count = 0;
19912 int prologue_call_count_second = 0;
19913 int epilogue_call_count_second = 0;
19914 int prologue_call_count_alloc = 0;
19915 int epilogue_call_count_alloc = 0;
19917 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
19918 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19919 ++prologue_call_count;
19923 void PrologueCallback(v8::Isolate* isolate,
19925 v8::GCCallbackFlags flags) {
19926 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19927 CHECK_EQ(gc_callbacks_isolate, isolate);
19928 ++prologue_call_count;
19932 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
19933 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19934 ++epilogue_call_count;
19938 void EpilogueCallback(v8::Isolate* isolate,
19940 v8::GCCallbackFlags flags) {
19941 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19942 CHECK_EQ(gc_callbacks_isolate, isolate);
19943 ++epilogue_call_count;
19947 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
19948 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19949 ++prologue_call_count_second;
19953 void PrologueCallbackSecond(v8::Isolate* isolate,
19955 v8::GCCallbackFlags flags) {
19956 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19957 CHECK_EQ(gc_callbacks_isolate, isolate);
19958 ++prologue_call_count_second;
19962 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
19963 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19964 ++epilogue_call_count_second;
19968 void EpilogueCallbackSecond(v8::Isolate* isolate,
19970 v8::GCCallbackFlags flags) {
19971 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19972 CHECK_EQ(gc_callbacks_isolate, isolate);
19973 ++epilogue_call_count_second;
19977 void PrologueCallbackAlloc(v8::Isolate* isolate,
19979 v8::GCCallbackFlags flags) {
19980 v8::HandleScope scope(isolate);
19982 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19983 CHECK_EQ(gc_callbacks_isolate, isolate);
19984 ++prologue_call_count_alloc;
19986 // Simulate full heap to see if we will reenter this callback
19987 SimulateFullSpace(CcTest::heap()->new_space());
19989 Local<Object> obj = Object::New(isolate);
19990 CHECK(!obj.IsEmpty());
19992 CcTest::heap()->CollectAllGarbage(
19993 i::Heap::kAbortIncrementalMarkingMask);
19997 void EpilogueCallbackAlloc(v8::Isolate* isolate,
19999 v8::GCCallbackFlags flags) {
20000 v8::HandleScope scope(isolate);
20002 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
20003 CHECK_EQ(gc_callbacks_isolate, isolate);
20004 ++epilogue_call_count_alloc;
20006 // Simulate full heap to see if we will reenter this callback
20007 SimulateFullSpace(CcTest::heap()->new_space());
20009 Local<Object> obj = Object::New(isolate);
20010 CHECK(!obj.IsEmpty());
20012 CcTest::heap()->CollectAllGarbage(
20013 i::Heap::kAbortIncrementalMarkingMask);
20017 TEST(GCCallbacksOld) {
20018 LocalContext context;
20020 v8::V8::AddGCPrologueCallback(PrologueCallback);
20021 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
20022 CHECK_EQ(0, prologue_call_count);
20023 CHECK_EQ(0, epilogue_call_count);
20024 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20025 CHECK_EQ(1, prologue_call_count);
20026 CHECK_EQ(1, epilogue_call_count);
20027 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
20028 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
20029 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20030 CHECK_EQ(2, prologue_call_count);
20031 CHECK_EQ(2, epilogue_call_count);
20032 CHECK_EQ(1, prologue_call_count_second);
20033 CHECK_EQ(1, epilogue_call_count_second);
20034 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
20035 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
20036 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20037 CHECK_EQ(2, prologue_call_count);
20038 CHECK_EQ(2, epilogue_call_count);
20039 CHECK_EQ(2, prologue_call_count_second);
20040 CHECK_EQ(2, epilogue_call_count_second);
20041 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
20042 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
20043 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20044 CHECK_EQ(2, prologue_call_count);
20045 CHECK_EQ(2, epilogue_call_count);
20046 CHECK_EQ(2, prologue_call_count_second);
20047 CHECK_EQ(2, epilogue_call_count_second);
20051 TEST(GCCallbacks) {
20052 LocalContext context;
20053 v8::Isolate* isolate = context->GetIsolate();
20054 gc_callbacks_isolate = isolate;
20055 isolate->AddGCPrologueCallback(PrologueCallback);
20056 isolate->AddGCEpilogueCallback(EpilogueCallback);
20057 CHECK_EQ(0, prologue_call_count);
20058 CHECK_EQ(0, epilogue_call_count);
20059 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20060 CHECK_EQ(1, prologue_call_count);
20061 CHECK_EQ(1, epilogue_call_count);
20062 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
20063 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
20064 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20065 CHECK_EQ(2, prologue_call_count);
20066 CHECK_EQ(2, epilogue_call_count);
20067 CHECK_EQ(1, prologue_call_count_second);
20068 CHECK_EQ(1, epilogue_call_count_second);
20069 isolate->RemoveGCPrologueCallback(PrologueCallback);
20070 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
20071 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20072 CHECK_EQ(2, prologue_call_count);
20073 CHECK_EQ(2, epilogue_call_count);
20074 CHECK_EQ(2, prologue_call_count_second);
20075 CHECK_EQ(2, epilogue_call_count_second);
20076 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
20077 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
20078 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20079 CHECK_EQ(2, prologue_call_count);
20080 CHECK_EQ(2, epilogue_call_count);
20081 CHECK_EQ(2, prologue_call_count_second);
20082 CHECK_EQ(2, epilogue_call_count_second);
20084 CHECK_EQ(0, prologue_call_count_alloc);
20085 CHECK_EQ(0, epilogue_call_count_alloc);
20086 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
20087 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
20088 CcTest::heap()->CollectAllGarbage(
20089 i::Heap::kAbortIncrementalMarkingMask);
20090 CHECK_EQ(1, prologue_call_count_alloc);
20091 CHECK_EQ(1, epilogue_call_count_alloc);
20092 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
20093 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
20097 THREADED_TEST(AddToJSFunctionResultCache) {
20098 i::FLAG_stress_compaction = false;
20099 i::FLAG_allow_natives_syntax = true;
20100 v8::HandleScope scope(CcTest::isolate());
20102 LocalContext context;
20108 " var r0 = %_GetFromCache(0, key0);"
20109 " var r1 = %_GetFromCache(0, key1);"
20110 " var r0_ = %_GetFromCache(0, key0);"
20112 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
20113 " var r1_ = %_GetFromCache(0, key1);"
20115 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
20116 " return 'PASSED';"
20118 CcTest::heap()->ClearJSFunctionResultCaches();
20119 ExpectString(code, "PASSED");
20123 THREADED_TEST(FillJSFunctionResultCache) {
20124 i::FLAG_allow_natives_syntax = true;
20125 LocalContext context;
20126 v8::HandleScope scope(context->GetIsolate());
20131 " var r = %_GetFromCache(0, k);"
20132 " for (var i = 0; i < 16; i++) {"
20133 " %_GetFromCache(0, 'a' + i);"
20135 " if (r === %_GetFromCache(0, k))"
20136 " return 'FAILED: k0CacheSize is too small';"
20137 " return 'PASSED';"
20139 CcTest::heap()->ClearJSFunctionResultCaches();
20140 ExpectString(code, "PASSED");
20144 THREADED_TEST(RoundRobinGetFromCache) {
20145 i::FLAG_allow_natives_syntax = true;
20146 LocalContext context;
20147 v8::HandleScope scope(context->GetIsolate());
20152 " for (var i = 0; i < 16; i++) keys.push(i);"
20153 " var values = [];"
20154 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
20155 " for (var i = 0; i < 16; i++) {"
20156 " var v = %_GetFromCache(0, keys[i]);"
20157 " if (v.toString() !== values[i].toString())"
20158 " return 'Wrong value for ' + "
20159 " keys[i] + ': ' + v + ' vs. ' + values[i];"
20161 " return 'PASSED';"
20163 CcTest::heap()->ClearJSFunctionResultCaches();
20164 ExpectString(code, "PASSED");
20168 THREADED_TEST(ReverseGetFromCache) {
20169 i::FLAG_allow_natives_syntax = true;
20170 LocalContext context;
20171 v8::HandleScope scope(context->GetIsolate());
20176 " for (var i = 0; i < 16; i++) keys.push(i);"
20177 " var values = [];"
20178 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
20179 " for (var i = 15; i >= 16; i--) {"
20180 " var v = %_GetFromCache(0, keys[i]);"
20181 " if (v !== values[i])"
20182 " return 'Wrong value for ' + "
20183 " keys[i] + ': ' + v + ' vs. ' + values[i];"
20185 " return 'PASSED';"
20187 CcTest::heap()->ClearJSFunctionResultCaches();
20188 ExpectString(code, "PASSED");
20192 THREADED_TEST(TestEviction) {
20193 i::FLAG_allow_natives_syntax = true;
20194 LocalContext context;
20195 v8::HandleScope scope(context->GetIsolate());
20199 " for (var i = 0; i < 2*16; i++) {"
20200 " %_GetFromCache(0, 'a' + i);"
20202 " return 'PASSED';"
20204 CcTest::heap()->ClearJSFunctionResultCaches();
20205 ExpectString(code, "PASSED");
20209 THREADED_TEST(TwoByteStringInOneByteCons) {
20210 // See Chromium issue 47824.
20211 LocalContext context;
20212 v8::HandleScope scope(context->GetIsolate());
20214 const char* init_code =
20215 "var str1 = 'abelspendabel';"
20216 "var str2 = str1 + str1 + str1;"
20218 Local<Value> result = CompileRun(init_code);
20220 Local<Value> indexof = CompileRun("str2.indexOf('els')");
20221 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
20223 CHECK(result->IsString());
20224 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
20225 int length = string->length();
20226 CHECK(string->IsOneByteRepresentation());
20228 i::Handle<i::String> flat_string = i::String::Flatten(string);
20230 CHECK(string->IsOneByteRepresentation());
20231 CHECK(flat_string->IsOneByteRepresentation());
20233 // Create external resource.
20234 uint16_t* uc16_buffer = new uint16_t[length + 1];
20236 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
20237 uc16_buffer[length] = 0;
20239 TestResource resource(uc16_buffer);
20241 flat_string->MakeExternal(&resource);
20243 CHECK(flat_string->IsTwoByteRepresentation());
20245 // If the cons string has been short-circuited, skip the following checks.
20246 if (!string.is_identical_to(flat_string)) {
20247 // At this point, we should have a Cons string which is flat and one-byte,
20248 // with a first half that is a two-byte string (although it only contains
20249 // one-byte characters). This is a valid sequence of steps, and it can
20250 // happen in real pages.
20251 CHECK(string->IsOneByteRepresentation());
20252 i::ConsString* cons = i::ConsString::cast(*string);
20253 CHECK_EQ(0, cons->second()->length());
20254 CHECK(cons->first()->IsTwoByteRepresentation());
20257 // Check that some string operations work.
20260 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
20261 CHECK_EQ(6, reresult->Int32Value());
20264 reresult = CompileRun("str2.match(/abe./g).length;");
20265 CHECK_EQ(6, reresult->Int32Value());
20267 reresult = CompileRun("str2.search(/bel/g);");
20268 CHECK_EQ(1, reresult->Int32Value());
20270 reresult = CompileRun("str2.search(/be./g);");
20271 CHECK_EQ(1, reresult->Int32Value());
20273 ExpectTrue("/bel/g.test(str2);");
20275 ExpectTrue("/be./g.test(str2);");
20277 reresult = CompileRun("/bel/g.exec(str2);");
20278 CHECK(!reresult->IsNull());
20280 reresult = CompileRun("/be./g.exec(str2);");
20281 CHECK(!reresult->IsNull());
20283 ExpectString("str2.substring(2, 10);", "elspenda");
20285 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
20287 ExpectString("str2.charAt(2);", "e");
20289 ExpectObject("str2.indexOf('els');", indexof);
20291 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
20293 reresult = CompileRun("str2.charCodeAt(2);");
20294 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
20298 TEST(ContainsOnlyOneByte) {
20299 v8::V8::Initialize();
20300 v8::Isolate* isolate = CcTest::isolate();
20301 v8::HandleScope scope(isolate);
20302 // Make a buffer long enough that it won't automatically be converted.
20303 const int length = 512;
20304 // Ensure word aligned assignment.
20305 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
20306 i::SmartArrayPointer<uintptr_t>
20307 aligned_contents(new uintptr_t[aligned_length]);
20308 uint16_t* string_contents =
20309 reinterpret_cast<uint16_t*>(aligned_contents.get());
20310 // Set to contain only one byte.
20311 for (int i = 0; i < length-1; i++) {
20312 string_contents[i] = 0x41;
20314 string_contents[length-1] = 0;
20316 Handle<String> string =
20317 String::NewExternal(isolate,
20318 new TestResource(string_contents, NULL, false));
20319 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20320 // Counter example.
20321 string = String::NewFromTwoByte(isolate, string_contents);
20322 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
20323 // Test left right and balanced cons strings.
20324 Handle<String> base = String::NewFromUtf8(isolate, "a");
20325 Handle<String> left = base;
20326 Handle<String> right = base;
20327 for (int i = 0; i < 1000; i++) {
20328 left = String::Concat(base, left);
20329 right = String::Concat(right, base);
20331 Handle<String> balanced = String::Concat(left, base);
20332 balanced = String::Concat(balanced, right);
20333 Handle<String> cons_strings[] = {left, balanced, right};
20334 Handle<String> two_byte =
20335 String::NewExternal(isolate,
20336 new TestResource(string_contents, NULL, false));
20337 USE(two_byte); USE(cons_strings);
20338 for (size_t i = 0; i < arraysize(cons_strings); i++) {
20339 // Base assumptions.
20340 string = cons_strings[i];
20341 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
20342 // Test left and right concatentation.
20343 string = String::Concat(two_byte, cons_strings[i]);
20344 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20345 string = String::Concat(cons_strings[i], two_byte);
20346 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
20348 // Set bits in different positions
20349 // for strings of different lengths and alignments.
20350 for (int alignment = 0; alignment < 7; alignment++) {
20351 for (int size = 2; alignment + size < length; size *= 2) {
20352 int zero_offset = size + alignment;
20353 string_contents[zero_offset] = 0;
20354 for (int i = 0; i < size; i++) {
20355 int shift = 8 + (i % 7);
20356 string_contents[alignment + i] = 1 << shift;
20357 string = String::NewExternal(
20359 new TestResource(string_contents + alignment, NULL, false));
20360 CHECK_EQ(size, string->Length());
20361 CHECK(!string->ContainsOnlyOneByte());
20362 string_contents[alignment + i] = 0x41;
20364 string_contents[zero_offset] = 0x41;
20370 // Failed access check callback that performs a GC on each invocation.
20371 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
20372 v8::AccessType type,
20373 Local<v8::Value> data) {
20374 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20378 TEST(GCInFailedAccessCheckCallback) {
20379 // Install a failed access check callback that performs a GC on each
20380 // invocation. Then force the callback to be called from va
20382 v8::V8::Initialize();
20383 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
20385 v8::Isolate* isolate = CcTest::isolate();
20386 v8::HandleScope scope(isolate);
20388 // Create an ObjectTemplate for global objects and install access
20389 // check callbacks that will block access.
20390 v8::Handle<v8::ObjectTemplate> global_template =
20391 v8::ObjectTemplate::New(isolate);
20392 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
20393 IndexedGetAccessBlocker,
20394 v8::Handle<v8::Value>(),
20397 // Create a context and set an x property on it's global object.
20398 LocalContext context0(NULL, global_template);
20399 context0->Global()->Set(v8_str("x"), v8_num(42));
20400 v8::Handle<v8::Object> global0 = context0->Global();
20402 // Create a context with a different security token so that the
20403 // failed access check callback will be called on each access.
20404 LocalContext context1(NULL, global_template);
20405 context1->Global()->Set(v8_str("other"), global0);
20407 // Get property with failed access check.
20408 ExpectUndefined("other.x");
20410 // Get element with failed access check.
20411 ExpectUndefined("other[0]");
20413 // Set property with failed access check.
20414 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
20415 CHECK(result->IsObject());
20417 // Set element with failed access check.
20418 result = CompileRun("other[0] = new Object()");
20419 CHECK(result->IsObject());
20421 // Get property attribute with failed access check.
20422 ExpectFalse("\'x\' in other");
20424 // Get property attribute for element with failed access check.
20425 ExpectFalse("0 in other");
20427 // Delete property.
20428 ExpectFalse("delete other.x");
20431 CHECK_EQ(false, global0->Delete(0));
20435 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
20437 // Define JavaScript accessor.
20438 ExpectUndefined("Object.prototype.__defineGetter__.call("
20439 " other, \'x\', function() { return 42; })");
20442 ExpectUndefined("Object.prototype.__lookupGetter__.call("
20446 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
20448 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
20449 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
20450 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
20452 // Reset the failed access check callback so it does not influence
20453 // the other tests.
20454 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
20458 TEST(IsolateNewDispose) {
20459 v8::Isolate* current_isolate = CcTest::isolate();
20460 v8::Isolate* isolate = v8::Isolate::New();
20461 CHECK(isolate != NULL);
20462 CHECK(current_isolate != isolate);
20463 CHECK(current_isolate == CcTest::isolate());
20465 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20466 last_location = last_message = NULL;
20467 isolate->Dispose();
20468 CHECK_EQ(last_location, NULL);
20469 CHECK_EQ(last_message, NULL);
20473 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
20474 v8::Isolate* isolate = v8::Isolate::New();
20476 v8::Isolate::Scope i_scope(isolate);
20477 v8::HandleScope scope(isolate);
20478 LocalContext context(isolate);
20479 // Run something in this isolate.
20480 ExpectTrue("true");
20481 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20482 last_location = last_message = NULL;
20483 // Still entered, should fail.
20484 isolate->Dispose();
20485 CHECK_NE(last_location, NULL);
20486 CHECK_NE(last_message, NULL);
20488 isolate->Dispose();
20492 TEST(RunTwoIsolatesOnSingleThread) {
20494 v8::Isolate* isolate1 = v8::Isolate::New();
20496 v8::Persistent<v8::Context> context1;
20498 v8::HandleScope scope(isolate1);
20499 context1.Reset(isolate1, Context::New(isolate1));
20503 v8::HandleScope scope(isolate1);
20504 v8::Local<v8::Context> context =
20505 v8::Local<v8::Context>::New(isolate1, context1);
20506 v8::Context::Scope context_scope(context);
20507 // Run something in new isolate.
20508 CompileRun("var foo = 'isolate 1';");
20509 ExpectString("function f() { return foo; }; f()", "isolate 1");
20513 v8::Isolate* isolate2 = v8::Isolate::New();
20514 v8::Persistent<v8::Context> context2;
20517 v8::Isolate::Scope iscope(isolate2);
20518 v8::HandleScope scope(isolate2);
20519 context2.Reset(isolate2, Context::New(isolate2));
20520 v8::Local<v8::Context> context =
20521 v8::Local<v8::Context>::New(isolate2, context2);
20522 v8::Context::Scope context_scope(context);
20524 // Run something in new isolate.
20525 CompileRun("var foo = 'isolate 2';");
20526 ExpectString("function f() { return foo; }; f()", "isolate 2");
20530 v8::HandleScope scope(isolate1);
20531 v8::Local<v8::Context> context =
20532 v8::Local<v8::Context>::New(isolate1, context1);
20533 v8::Context::Scope context_scope(context);
20534 // Now again in isolate 1
20535 ExpectString("function f() { return foo; }; f()", "isolate 1");
20540 // Run some stuff in default isolate.
20541 v8::Persistent<v8::Context> context_default;
20543 v8::Isolate* isolate = CcTest::isolate();
20544 v8::Isolate::Scope iscope(isolate);
20545 v8::HandleScope scope(isolate);
20546 context_default.Reset(isolate, Context::New(isolate));
20550 v8::HandleScope scope(CcTest::isolate());
20551 v8::Local<v8::Context> context =
20552 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20553 v8::Context::Scope context_scope(context);
20554 // Variables in other isolates should be not available, verify there
20555 // is an exception.
20556 ExpectTrue("function f() {"
20564 "var isDefaultIsolate = true;"
20571 v8::Isolate::Scope iscope(isolate2);
20572 v8::HandleScope scope(isolate2);
20573 v8::Local<v8::Context> context =
20574 v8::Local<v8::Context>::New(isolate2, context2);
20575 v8::Context::Scope context_scope(context);
20576 ExpectString("function f() { return foo; }; f()", "isolate 2");
20580 v8::HandleScope scope(v8::Isolate::GetCurrent());
20581 v8::Local<v8::Context> context =
20582 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
20583 v8::Context::Scope context_scope(context);
20584 ExpectString("function f() { return foo; }; f()", "isolate 1");
20588 v8::Isolate::Scope iscope(isolate2);
20595 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20596 last_location = last_message = NULL;
20598 isolate1->Dispose();
20599 CHECK_EQ(last_location, NULL);
20600 CHECK_EQ(last_message, NULL);
20602 isolate2->Dispose();
20603 CHECK_EQ(last_location, NULL);
20604 CHECK_EQ(last_message, NULL);
20606 // Check that default isolate still runs.
20608 v8::HandleScope scope(CcTest::isolate());
20609 v8::Local<v8::Context> context =
20610 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20611 v8::Context::Scope context_scope(context);
20612 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
20617 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
20618 v8::Isolate::Scope isolate_scope(isolate);
20619 v8::HandleScope scope(isolate);
20620 LocalContext context(isolate);
20621 i::ScopedVector<char> code(1024);
20622 i::SNPrintF(code, "function fib(n) {"
20623 " if (n <= 2) return 1;"
20624 " return fib(n-1) + fib(n-2);"
20627 Local<Value> value = CompileRun(code.start());
20628 CHECK(value->IsNumber());
20629 return static_cast<int>(value->NumberValue());
20632 class IsolateThread : public v8::base::Thread {
20634 explicit IsolateThread(int fib_limit)
20635 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
20638 v8::Isolate* isolate = v8::Isolate::New();
20639 result_ = CalcFibonacci(isolate, fib_limit_);
20640 isolate->Dispose();
20643 int result() { return result_; }
20651 TEST(MultipleIsolatesOnIndividualThreads) {
20652 IsolateThread thread1(21);
20653 IsolateThread thread2(12);
20655 // Compute some fibonacci numbers on 3 threads in 3 isolates.
20659 int result1 = CalcFibonacci(CcTest::isolate(), 21);
20660 int result2 = CalcFibonacci(CcTest::isolate(), 12);
20665 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
20666 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
20667 CHECK_EQ(result1, 10946);
20668 CHECK_EQ(result2, 144);
20669 CHECK_EQ(result1, thread1.result());
20670 CHECK_EQ(result2, thread2.result());
20674 TEST(IsolateDifferentContexts) {
20675 v8::Isolate* isolate = v8::Isolate::New();
20676 Local<v8::Context> context;
20678 v8::Isolate::Scope isolate_scope(isolate);
20679 v8::HandleScope handle_scope(isolate);
20680 context = v8::Context::New(isolate);
20681 v8::Context::Scope context_scope(context);
20682 Local<Value> v = CompileRun("2");
20683 CHECK(v->IsNumber());
20684 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
20687 v8::Isolate::Scope isolate_scope(isolate);
20688 v8::HandleScope handle_scope(isolate);
20689 context = v8::Context::New(isolate);
20690 v8::Context::Scope context_scope(context);
20691 Local<Value> v = CompileRun("22");
20692 CHECK(v->IsNumber());
20693 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
20695 isolate->Dispose();
20698 class InitDefaultIsolateThread : public v8::base::Thread {
20701 SetResourceConstraints,
20703 SetCounterFunction,
20704 SetCreateHistogramFunction,
20705 SetAddHistogramSampleFunction
20708 explicit InitDefaultIsolateThread(TestCase testCase)
20709 : Thread(Options("InitDefaultIsolateThread")),
20710 testCase_(testCase),
20714 v8::Isolate::CreateParams create_params;
20715 switch (testCase_) {
20716 case SetResourceConstraints: {
20717 create_params.constraints.set_max_semi_space_size(1);
20718 create_params.constraints.set_max_old_space_size(4);
20724 v8::Isolate* isolate = v8::Isolate::New(create_params);
20726 switch (testCase_) {
20727 case SetResourceConstraints:
20728 // Already handled in pre-Isolate-creation block.
20731 case SetFatalHandler:
20732 v8::V8::SetFatalErrorHandler(NULL);
20735 case SetCounterFunction:
20736 CcTest::isolate()->SetCounterFunction(NULL);
20739 case SetCreateHistogramFunction:
20740 CcTest::isolate()->SetCreateHistogramFunction(NULL);
20743 case SetAddHistogramSampleFunction:
20744 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
20748 isolate->Dispose();
20752 bool result() { return result_; }
20755 TestCase testCase_;
20760 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
20761 InitDefaultIsolateThread thread(testCase);
20764 CHECK_EQ(thread.result(), true);
20768 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
20769 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
20773 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
20774 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
20778 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
20779 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
20783 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
20784 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
20788 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
20789 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
20793 TEST(StringCheckMultipleContexts) {
20795 "(function() { return \"a\".charAt(0); })()";
20798 // Run the code twice in the first context to initialize the call IC.
20799 LocalContext context1;
20800 v8::HandleScope scope(context1->GetIsolate());
20801 ExpectString(code, "a");
20802 ExpectString(code, "a");
20806 // Change the String.prototype in the second context and check
20807 // that the right function gets called.
20808 LocalContext context2;
20809 v8::HandleScope scope(context2->GetIsolate());
20810 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
20811 ExpectString(code, "not a");
20816 TEST(NumberCheckMultipleContexts) {
20818 "(function() { return (42).toString(); })()";
20821 // Run the code twice in the first context to initialize the call IC.
20822 LocalContext context1;
20823 v8::HandleScope scope(context1->GetIsolate());
20824 ExpectString(code, "42");
20825 ExpectString(code, "42");
20829 // Change the Number.prototype in the second context and check
20830 // that the right function gets called.
20831 LocalContext context2;
20832 v8::HandleScope scope(context2->GetIsolate());
20833 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
20834 ExpectString(code, "not 42");
20839 TEST(BooleanCheckMultipleContexts) {
20841 "(function() { return true.toString(); })()";
20844 // Run the code twice in the first context to initialize the call IC.
20845 LocalContext context1;
20846 v8::HandleScope scope(context1->GetIsolate());
20847 ExpectString(code, "true");
20848 ExpectString(code, "true");
20852 // Change the Boolean.prototype in the second context and check
20853 // that the right function gets called.
20854 LocalContext context2;
20855 v8::HandleScope scope(context2->GetIsolate());
20856 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
20857 ExpectString(code, "");
20862 TEST(DontDeleteCellLoadIC) {
20863 const char* function_code =
20864 "function readCell() { while (true) { return cell; } }";
20867 // Run the code twice in the first context to initialize the load
20868 // IC for a don't delete cell.
20869 LocalContext context1;
20870 v8::HandleScope scope(context1->GetIsolate());
20871 CompileRun("var cell = \"first\";");
20872 ExpectBoolean("delete cell", false);
20873 CompileRun(function_code);
20874 ExpectString("readCell()", "first");
20875 ExpectString("readCell()", "first");
20879 // Use a deletable cell in the second context.
20880 LocalContext context2;
20881 v8::HandleScope scope(context2->GetIsolate());
20882 CompileRun("cell = \"second\";");
20883 CompileRun(function_code);
20884 ExpectString("readCell()", "second");
20885 ExpectBoolean("delete cell", true);
20886 ExpectString("(function() {"
20888 " return readCell();"
20890 " return e.toString();"
20893 "ReferenceError: cell is not defined");
20894 CompileRun("cell = \"new_second\";");
20895 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20896 ExpectString("readCell()", "new_second");
20897 ExpectString("readCell()", "new_second");
20902 TEST(DontDeleteCellLoadICForceDelete) {
20903 const char* function_code =
20904 "function readCell() { while (true) { return cell; } }";
20906 // Run the code twice to initialize the load IC for a don't delete
20908 LocalContext context;
20909 v8::HandleScope scope(context->GetIsolate());
20910 CompileRun("var cell = \"value\";");
20911 ExpectBoolean("delete cell", false);
20912 CompileRun(function_code);
20913 ExpectString("readCell()", "value");
20914 ExpectString("readCell()", "value");
20916 // Delete the cell using the API and check the inlined code works
20918 CHECK(context->Global()->ForceDelete(v8_str("cell")));
20919 ExpectString("(function() {"
20921 " return readCell();"
20923 " return e.toString();"
20926 "ReferenceError: cell is not defined");
20930 TEST(DontDeleteCellLoadICAPI) {
20931 const char* function_code =
20932 "function readCell() { while (true) { return cell; } }";
20934 // Run the code twice to initialize the load IC for a don't delete
20935 // cell created using the API.
20936 LocalContext context;
20937 v8::HandleScope scope(context->GetIsolate());
20938 context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
20939 ExpectBoolean("delete cell", false);
20940 CompileRun(function_code);
20941 ExpectString("readCell()", "value");
20942 ExpectString("readCell()", "value");
20944 // Delete the cell using the API and check the inlined code works
20946 CHECK(context->Global()->ForceDelete(v8_str("cell")));
20947 ExpectString("(function() {"
20949 " return readCell();"
20951 " return e.toString();"
20954 "ReferenceError: cell is not defined");
20958 class Visitor42 : public v8::PersistentHandleVisitor {
20960 explicit Visitor42(v8::Persistent<v8::Object>* object)
20961 : counter_(0), object_(object) { }
20963 virtual void VisitPersistentHandle(Persistent<Value>* value,
20964 uint16_t class_id) {
20965 if (class_id != 42) return;
20966 CHECK_EQ(42, value->WrapperClassId());
20967 v8::Isolate* isolate = CcTest::isolate();
20968 v8::HandleScope handle_scope(isolate);
20969 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
20970 v8::Handle<v8::Value> object =
20971 v8::Local<v8::Object>::New(isolate, *object_);
20972 CHECK(handle->IsObject());
20973 CHECK_EQ(Handle<Object>::Cast(handle), object);
20978 v8::Persistent<v8::Object>* object_;
20982 TEST(PersistentHandleVisitor) {
20983 LocalContext context;
20984 v8::Isolate* isolate = context->GetIsolate();
20985 v8::HandleScope scope(isolate);
20986 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20987 CHECK_EQ(0, object.WrapperClassId());
20988 object.SetWrapperClassId(42);
20989 CHECK_EQ(42, object.WrapperClassId());
20991 Visitor42 visitor(&object);
20992 v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
20993 CHECK_EQ(1, visitor.counter_);
20999 TEST(WrapperClassId) {
21000 LocalContext context;
21001 v8::Isolate* isolate = context->GetIsolate();
21002 v8::HandleScope scope(isolate);
21003 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
21004 CHECK_EQ(0, object.WrapperClassId());
21005 object.SetWrapperClassId(65535);
21006 CHECK_EQ(65535, object.WrapperClassId());
21011 TEST(PersistentHandleInNewSpaceVisitor) {
21012 LocalContext context;
21013 v8::Isolate* isolate = context->GetIsolate();
21014 v8::HandleScope scope(isolate);
21015 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
21016 CHECK_EQ(0, object1.WrapperClassId());
21017 object1.SetWrapperClassId(42);
21018 CHECK_EQ(42, object1.WrapperClassId());
21020 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
21021 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
21023 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
21024 CHECK_EQ(0, object2.WrapperClassId());
21025 object2.SetWrapperClassId(42);
21026 CHECK_EQ(42, object2.WrapperClassId());
21028 Visitor42 visitor(&object2);
21029 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
21030 CHECK_EQ(1, visitor.counter_);
21038 LocalContext context;
21039 v8::HandleScope scope(context->GetIsolate());
21041 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
21042 CHECK(re->IsRegExp());
21043 CHECK(re->GetSource()->Equals(v8_str("foo")));
21044 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
21046 re = v8::RegExp::New(v8_str("bar"),
21047 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21048 v8::RegExp::kGlobal));
21049 CHECK(re->IsRegExp());
21050 CHECK(re->GetSource()->Equals(v8_str("bar")));
21051 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
21052 static_cast<int>(re->GetFlags()));
21054 re = v8::RegExp::New(v8_str("baz"),
21055 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21056 v8::RegExp::kMultiline));
21057 CHECK(re->IsRegExp());
21058 CHECK(re->GetSource()->Equals(v8_str("baz")));
21059 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
21060 static_cast<int>(re->GetFlags()));
21062 re = CompileRun("/quux/").As<v8::RegExp>();
21063 CHECK(re->IsRegExp());
21064 CHECK(re->GetSource()->Equals(v8_str("quux")));
21065 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
21067 re = CompileRun("/quux/gm").As<v8::RegExp>();
21068 CHECK(re->IsRegExp());
21069 CHECK(re->GetSource()->Equals(v8_str("quux")));
21070 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
21071 static_cast<int>(re->GetFlags()));
21073 // Override the RegExp constructor and check the API constructor
21075 CompileRun("RegExp = function() {}");
21077 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
21078 CHECK(re->IsRegExp());
21079 CHECK(re->GetSource()->Equals(v8_str("foobar")));
21080 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
21082 re = v8::RegExp::New(v8_str("foobarbaz"),
21083 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
21084 v8::RegExp::kMultiline));
21085 CHECK(re->IsRegExp());
21086 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
21087 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
21088 static_cast<int>(re->GetFlags()));
21090 context->Global()->Set(v8_str("re"), re);
21091 ExpectTrue("re.test('FoobarbaZ')");
21093 // RegExps are objects on which you can set properties.
21094 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
21095 v8::Handle<v8::Value> value(CompileRun("re.property"));
21096 CHECK_EQ(32, value->Int32Value());
21098 v8::TryCatch try_catch;
21099 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
21100 CHECK(re.IsEmpty());
21101 CHECK(try_catch.HasCaught());
21102 context->Global()->Set(v8_str("ex"), try_catch.Exception());
21103 ExpectTrue("ex instanceof SyntaxError");
21107 THREADED_TEST(Equals) {
21108 LocalContext localContext;
21109 v8::HandleScope handleScope(localContext->GetIsolate());
21111 v8::Handle<v8::Object> globalProxy = localContext->Global();
21112 v8::Handle<Value> global = globalProxy->GetPrototype();
21114 CHECK(global->StrictEquals(global));
21115 CHECK(!global->StrictEquals(globalProxy));
21116 CHECK(!globalProxy->StrictEquals(global));
21117 CHECK(globalProxy->StrictEquals(globalProxy));
21119 CHECK(global->Equals(global));
21120 CHECK(!global->Equals(globalProxy));
21121 CHECK(!globalProxy->Equals(global));
21122 CHECK(globalProxy->Equals(globalProxy));
21126 static void Getter(v8::Local<v8::Name> property,
21127 const v8::PropertyCallbackInfo<v8::Value>& info) {
21128 info.GetReturnValue().Set(v8_str("42!"));
21132 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
21133 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
21134 result->Set(0, v8_str("universalAnswer"));
21135 info.GetReturnValue().Set(result);
21139 TEST(NamedEnumeratorAndForIn) {
21140 LocalContext context;
21141 v8::Isolate* isolate = context->GetIsolate();
21142 v8::HandleScope handle_scope(isolate);
21143 v8::Context::Scope context_scope(context.local());
21145 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
21146 tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
21147 NULL, Enumerator));
21148 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
21149 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
21150 "var result = []; for (var k in o) result.push(k); result"));
21151 CHECK_EQ(1, result->Length());
21152 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
21156 TEST(DefinePropertyPostDetach) {
21157 LocalContext context;
21158 v8::HandleScope scope(context->GetIsolate());
21159 v8::Handle<v8::Object> proxy = context->Global();
21160 v8::Handle<v8::Function> define_property =
21161 CompileRun("(function() {"
21162 " Object.defineProperty("
21165 " { configurable: true, enumerable: true, value: 3 });"
21166 "})").As<Function>();
21167 context->DetachGlobal();
21168 define_property->Call(proxy, 0, NULL);
21172 static void InstallContextId(v8::Handle<Context> context, int id) {
21173 Context::Scope scope(context);
21174 CompileRun("Object.prototype").As<Object>()->
21175 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
21179 static void CheckContextId(v8::Handle<Object> object, int expected) {
21180 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
21184 THREADED_TEST(CreationContext) {
21185 v8::Isolate* isolate = CcTest::isolate();
21186 HandleScope handle_scope(isolate);
21187 Handle<Context> context1 = Context::New(isolate);
21188 InstallContextId(context1, 1);
21189 Handle<Context> context2 = Context::New(isolate);
21190 InstallContextId(context2, 2);
21191 Handle<Context> context3 = Context::New(isolate);
21192 InstallContextId(context3, 3);
21194 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
21196 Local<Object> object1;
21197 Local<Function> func1;
21199 Context::Scope scope(context1);
21200 object1 = Object::New(isolate);
21201 func1 = tmpl->GetFunction();
21204 Local<Object> object2;
21205 Local<Function> func2;
21207 Context::Scope scope(context2);
21208 object2 = Object::New(isolate);
21209 func2 = tmpl->GetFunction();
21212 Local<Object> instance1;
21213 Local<Object> instance2;
21216 Context::Scope scope(context3);
21217 instance1 = func1->NewInstance();
21218 instance2 = func2->NewInstance();
21221 CHECK(object1->CreationContext() == context1);
21222 CheckContextId(object1, 1);
21223 CHECK(func1->CreationContext() == context1);
21224 CheckContextId(func1, 1);
21225 CHECK(instance1->CreationContext() == context1);
21226 CheckContextId(instance1, 1);
21227 CHECK(object2->CreationContext() == context2);
21228 CheckContextId(object2, 2);
21229 CHECK(func2->CreationContext() == context2);
21230 CheckContextId(func2, 2);
21231 CHECK(instance2->CreationContext() == context2);
21232 CheckContextId(instance2, 2);
21235 Context::Scope scope(context1);
21236 CHECK(object1->CreationContext() == context1);
21237 CheckContextId(object1, 1);
21238 CHECK(func1->CreationContext() == context1);
21239 CheckContextId(func1, 1);
21240 CHECK(instance1->CreationContext() == context1);
21241 CheckContextId(instance1, 1);
21242 CHECK(object2->CreationContext() == context2);
21243 CheckContextId(object2, 2);
21244 CHECK(func2->CreationContext() == context2);
21245 CheckContextId(func2, 2);
21246 CHECK(instance2->CreationContext() == context2);
21247 CheckContextId(instance2, 2);
21251 Context::Scope scope(context2);
21252 CHECK(object1->CreationContext() == context1);
21253 CheckContextId(object1, 1);
21254 CHECK(func1->CreationContext() == context1);
21255 CheckContextId(func1, 1);
21256 CHECK(instance1->CreationContext() == context1);
21257 CheckContextId(instance1, 1);
21258 CHECK(object2->CreationContext() == context2);
21259 CheckContextId(object2, 2);
21260 CHECK(func2->CreationContext() == context2);
21261 CheckContextId(func2, 2);
21262 CHECK(instance2->CreationContext() == context2);
21263 CheckContextId(instance2, 2);
21268 THREADED_TEST(CreationContextOfJsFunction) {
21269 HandleScope handle_scope(CcTest::isolate());
21270 Handle<Context> context = Context::New(CcTest::isolate());
21271 InstallContextId(context, 1);
21273 Local<Object> function;
21275 Context::Scope scope(context);
21276 function = CompileRun("function foo() {}; foo").As<Object>();
21279 CHECK(function->CreationContext() == context);
21280 CheckContextId(function, 1);
21284 void HasOwnPropertyIndexedPropertyGetter(
21286 const v8::PropertyCallbackInfo<v8::Value>& info) {
21287 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
21291 void HasOwnPropertyNamedPropertyGetter(
21292 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
21293 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
21297 void HasOwnPropertyIndexedPropertyQuery(
21298 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21299 if (index == 42) info.GetReturnValue().Set(1);
21303 void HasOwnPropertyNamedPropertyQuery(
21304 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21305 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
21309 void HasOwnPropertyNamedPropertyQuery2(
21310 Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
21311 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
21315 void HasOwnPropertyAccessorGetter(
21316 Local<String> property,
21317 const v8::PropertyCallbackInfo<v8::Value>& info) {
21318 info.GetReturnValue().Set(v8_str("yes"));
21322 TEST(HasOwnProperty) {
21324 v8::Isolate* isolate = env->GetIsolate();
21325 v8::HandleScope scope(isolate);
21326 { // Check normal properties and defined getters.
21327 Handle<Value> value = CompileRun(
21330 " this.__defineGetter__('baz', function() { return 1; });"
21332 "function Bar() { "
21334 " this.__defineGetter__('bla', function() { return 2; });"
21336 "Bar.prototype = new Foo();"
21338 CHECK(value->IsObject());
21339 Handle<Object> object = value->ToObject(isolate);
21340 CHECK(object->Has(v8_str("foo")));
21341 CHECK(!object->HasOwnProperty(v8_str("foo")));
21342 CHECK(object->HasOwnProperty(v8_str("bar")));
21343 CHECK(object->Has(v8_str("baz")));
21344 CHECK(!object->HasOwnProperty(v8_str("baz")));
21345 CHECK(object->HasOwnProperty(v8_str("bla")));
21347 { // Check named getter interceptors.
21348 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21349 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21350 HasOwnPropertyNamedPropertyGetter));
21351 Handle<Object> instance = templ->NewInstance();
21352 CHECK(!instance->HasOwnProperty(v8_str("42")));
21353 CHECK(instance->HasOwnProperty(v8_str("foo")));
21354 CHECK(!instance->HasOwnProperty(v8_str("bar")));
21356 { // Check indexed getter interceptors.
21357 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21358 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21359 HasOwnPropertyIndexedPropertyGetter));
21360 Handle<Object> instance = templ->NewInstance();
21361 CHECK(instance->HasOwnProperty(v8_str("42")));
21362 CHECK(!instance->HasOwnProperty(v8_str("43")));
21363 CHECK(!instance->HasOwnProperty(v8_str("foo")));
21365 { // Check named query interceptors.
21366 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21367 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21368 0, 0, HasOwnPropertyNamedPropertyQuery));
21369 Handle<Object> instance = templ->NewInstance();
21370 CHECK(instance->HasOwnProperty(v8_str("foo")));
21371 CHECK(!instance->HasOwnProperty(v8_str("bar")));
21373 { // Check indexed query interceptors.
21374 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21375 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21376 0, 0, HasOwnPropertyIndexedPropertyQuery));
21377 Handle<Object> instance = templ->NewInstance();
21378 CHECK(instance->HasOwnProperty(v8_str("42")));
21379 CHECK(!instance->HasOwnProperty(v8_str("41")));
21381 { // Check callbacks.
21382 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21383 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
21384 Handle<Object> instance = templ->NewInstance();
21385 CHECK(instance->HasOwnProperty(v8_str("foo")));
21386 CHECK(!instance->HasOwnProperty(v8_str("bar")));
21388 { // Check that query wins on disagreement.
21389 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21390 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
21391 HasOwnPropertyNamedPropertyGetter, 0,
21392 HasOwnPropertyNamedPropertyQuery2));
21393 Handle<Object> instance = templ->NewInstance();
21394 CHECK(!instance->HasOwnProperty(v8_str("foo")));
21395 CHECK(instance->HasOwnProperty(v8_str("bar")));
21400 TEST(IndexedInterceptorWithStringProto) {
21401 v8::Isolate* isolate = CcTest::isolate();
21402 v8::HandleScope scope(isolate);
21403 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21404 templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
21405 NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
21406 LocalContext context;
21407 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21408 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
21409 // These should be intercepted.
21410 CHECK(CompileRun("42 in obj")->BooleanValue());
21411 CHECK(CompileRun("'42' in obj")->BooleanValue());
21412 // These should fall through to the String prototype.
21413 CHECK(CompileRun("0 in obj")->BooleanValue());
21414 CHECK(CompileRun("'0' in obj")->BooleanValue());
21415 // And these should both fail.
21416 CHECK(!CompileRun("32 in obj")->BooleanValue());
21417 CHECK(!CompileRun("'32' in obj")->BooleanValue());
21421 void CheckCodeGenerationAllowed() {
21422 Handle<Value> result = CompileRun("eval('42')");
21423 CHECK_EQ(42, result->Int32Value());
21424 result = CompileRun("(function(e) { return e('42'); })(eval)");
21425 CHECK_EQ(42, result->Int32Value());
21426 result = CompileRun("var f = new Function('return 42'); f()");
21427 CHECK_EQ(42, result->Int32Value());
21431 void CheckCodeGenerationDisallowed() {
21432 TryCatch try_catch;
21434 Handle<Value> result = CompileRun("eval('42')");
21435 CHECK(result.IsEmpty());
21436 CHECK(try_catch.HasCaught());
21439 result = CompileRun("(function(e) { return e('42'); })(eval)");
21440 CHECK(result.IsEmpty());
21441 CHECK(try_catch.HasCaught());
21444 result = CompileRun("var f = new Function('return 42'); f()");
21445 CHECK(result.IsEmpty());
21446 CHECK(try_catch.HasCaught());
21450 bool CodeGenerationAllowed(Local<Context> context) {
21451 ApiTestFuzzer::Fuzz();
21456 bool CodeGenerationDisallowed(Local<Context> context) {
21457 ApiTestFuzzer::Fuzz();
21462 THREADED_TEST(AllowCodeGenFromStrings) {
21463 LocalContext context;
21464 v8::HandleScope scope(context->GetIsolate());
21466 // eval and the Function constructor allowed by default.
21467 CHECK(context->IsCodeGenerationFromStringsAllowed());
21468 CheckCodeGenerationAllowed();
21470 // Disallow eval and the Function constructor.
21471 context->AllowCodeGenerationFromStrings(false);
21472 CHECK(!context->IsCodeGenerationFromStringsAllowed());
21473 CheckCodeGenerationDisallowed();
21476 context->AllowCodeGenerationFromStrings(true);
21477 CheckCodeGenerationAllowed();
21479 // Disallow but setting a global callback that will allow the calls.
21480 context->AllowCodeGenerationFromStrings(false);
21481 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
21482 CHECK(!context->IsCodeGenerationFromStringsAllowed());
21483 CheckCodeGenerationAllowed();
21485 // Set a callback that disallows the code generation.
21486 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
21487 CHECK(!context->IsCodeGenerationFromStringsAllowed());
21488 CheckCodeGenerationDisallowed();
21492 TEST(SetErrorMessageForCodeGenFromStrings) {
21493 LocalContext context;
21494 v8::HandleScope scope(context->GetIsolate());
21495 TryCatch try_catch;
21497 Handle<String> message = v8_str("Message") ;
21498 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
21499 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
21500 context->AllowCodeGenerationFromStrings(false);
21501 context->SetErrorMessageForCodeGenerationFromStrings(message);
21502 Handle<Value> result = CompileRun("eval('42')");
21503 CHECK(result.IsEmpty());
21504 CHECK(try_catch.HasCaught());
21505 Handle<String> actual_message = try_catch.Message()->Get();
21506 CHECK(expected_message->Equals(actual_message));
21510 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
21514 THREADED_TEST(CallAPIFunctionOnNonObject) {
21515 LocalContext context;
21516 v8::Isolate* isolate = context->GetIsolate();
21517 v8::HandleScope scope(isolate);
21518 Handle<FunctionTemplate> templ =
21519 v8::FunctionTemplate::New(isolate, NonObjectThis);
21520 Handle<Function> function = templ->GetFunction();
21521 context->Global()->Set(v8_str("f"), function);
21522 TryCatch try_catch;
21523 CompileRun("f.call(2)");
21527 // Regression test for issue 1470.
21528 THREADED_TEST(ReadOnlyIndexedProperties) {
21529 v8::Isolate* isolate = CcTest::isolate();
21530 v8::HandleScope scope(isolate);
21531 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21533 LocalContext context;
21534 Local<v8::Object> obj = templ->NewInstance();
21535 context->Global()->Set(v8_str("obj"), obj);
21536 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
21537 obj->Set(v8_str("1"), v8_str("foobar"));
21538 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
21539 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
21540 obj->Set(v8_num(2), v8_str("foobar"));
21541 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
21543 // Test non-smi case.
21544 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
21545 obj->Set(v8_str("2000000000"), v8_str("foobar"));
21546 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
21550 static int CountLiveMapsInMapCache(i::Context* context) {
21551 i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
21552 int length = map_cache->length();
21554 for (int i = 0; i < length; i++) {
21555 i::Object* value = map_cache->get(i);
21556 if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
21562 THREADED_TEST(Regress1516) {
21563 LocalContext context;
21564 v8::HandleScope scope(context->GetIsolate());
21566 // Object with 20 properties is not a common case, so it should be removed
21567 // from the cache after GC.
21568 { v8::HandleScope temp_scope(context->GetIsolate());
21571 "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
21572 "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
21573 "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
21574 "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
21578 int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
21579 CHECK_LE(1, elements);
21581 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
21583 CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
21587 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
21589 v8::AccessType type,
21590 Local<Value> data) {
21591 // Only block read access to __proto__.
21592 if (type == v8::ACCESS_GET && name->IsString() &&
21593 name.As<v8::String>()->Length() == 9 &&
21594 name.As<v8::String>()->Utf8Length() == 9) {
21596 CHECK_EQ(10, name.As<v8::String>()->WriteUtf8(buffer));
21597 return strncmp(buffer, "__proto__", 9) != 0;
21604 THREADED_TEST(Regress93759) {
21605 v8::Isolate* isolate = CcTest::isolate();
21606 HandleScope scope(isolate);
21608 // Template for object with security check.
21609 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
21610 // We don't do indexing, so any callback can be used for that.
21611 no_proto_template->SetAccessCheckCallbacks(
21612 BlockProtoNamedSecurityTestCallback,
21613 IndexedSecurityTestCallback);
21615 // Templates for objects with hidden prototypes and possibly security check.
21616 Local<FunctionTemplate> hidden_proto_template =
21617 v8::FunctionTemplate::New(isolate);
21618 hidden_proto_template->SetHiddenPrototype(true);
21620 Local<FunctionTemplate> protected_hidden_proto_template =
21621 v8::FunctionTemplate::New(isolate);
21622 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
21623 BlockProtoNamedSecurityTestCallback,
21624 IndexedSecurityTestCallback);
21625 protected_hidden_proto_template->SetHiddenPrototype(true);
21627 // Context for "foreign" objects used in test.
21628 Local<Context> context = v8::Context::New(isolate);
21631 // Plain object, no security check.
21632 Local<Object> simple_object = Object::New(isolate);
21634 // Object with explicit security check.
21635 Local<Object> protected_object =
21636 no_proto_template->NewInstance();
21638 // JSGlobalProxy object, always have security check.
21639 Local<Object> proxy_object =
21642 // Global object, the prototype of proxy_object. No security checks.
21643 Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
21645 // Hidden prototype without security check.
21646 Local<Object> hidden_prototype =
21647 hidden_proto_template->GetFunction()->NewInstance();
21648 Local<Object> object_with_hidden =
21649 Object::New(isolate);
21650 object_with_hidden->SetPrototype(hidden_prototype);
21652 // Hidden prototype with security check on the hidden prototype.
21653 Local<Object> protected_hidden_prototype =
21654 protected_hidden_proto_template->GetFunction()->NewInstance();
21655 Local<Object> object_with_protected_hidden =
21656 Object::New(isolate);
21657 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
21661 // Template for object for second context. Values to test are put on it as
21663 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
21664 global_template->Set(v8_str("simple"), simple_object);
21665 global_template->Set(v8_str("protected"), protected_object);
21666 global_template->Set(v8_str("global"), global_object);
21667 global_template->Set(v8_str("proxy"), proxy_object);
21668 global_template->Set(v8_str("hidden"), object_with_hidden);
21669 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
21671 LocalContext context2(NULL, global_template);
21673 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
21674 CHECK(result1->Equals(simple_object->GetPrototype()));
21676 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
21677 CHECK(result2.IsEmpty());
21679 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
21680 CHECK(result3->Equals(global_object->GetPrototype()));
21682 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
21683 CHECK(result4.IsEmpty());
21685 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
21686 CHECK(result5->Equals(
21687 object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
21689 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
21690 CHECK(result6.IsEmpty());
21694 THREADED_TEST(Regress125988) {
21695 v8::HandleScope scope(CcTest::isolate());
21696 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
21697 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
21699 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
21700 CompileRun("var a = new Object();"
21701 "var b = new Intercept();"
21702 "var c = new Object();"
21706 "for (var i = 0; i < 3; i++) c.x;");
21707 ExpectBoolean("c.hasOwnProperty('x')", false);
21708 ExpectInt32("c.x", 23);
21709 CompileRun("a.y = 42;"
21710 "for (var i = 0; i < 3; i++) c.x;");
21711 ExpectBoolean("c.hasOwnProperty('x')", false);
21712 ExpectInt32("c.x", 23);
21713 ExpectBoolean("c.hasOwnProperty('y')", false);
21714 ExpectInt32("c.y", 42);
21718 static void TestReceiver(Local<Value> expected_result,
21719 Local<Value> expected_receiver,
21720 const char* code) {
21721 Local<Value> result = CompileRun(code);
21722 CHECK(result->IsObject());
21723 CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
21724 CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
21728 THREADED_TEST(ForeignFunctionReceiver) {
21729 v8::Isolate* isolate = CcTest::isolate();
21730 HandleScope scope(isolate);
21732 // Create two contexts with different "id" properties ('i' and 'o').
21733 // Call a function both from its own context and from a the foreign
21734 // context, and see what "this" is bound to (returning both "this"
21735 // and "this.id" for comparison).
21737 Local<Context> foreign_context = v8::Context::New(isolate);
21738 foreign_context->Enter();
21739 Local<Value> foreign_function =
21740 CompileRun("function func() { return { 0: this.id, "
21742 " toString: function() { "
21749 CHECK(foreign_function->IsFunction());
21750 foreign_context->Exit();
21752 LocalContext context;
21754 Local<String> password = v8_str("Password");
21755 // Don't get hit by security checks when accessing foreign_context's
21756 // global receiver (aka. global proxy).
21757 context->SetSecurityToken(password);
21758 foreign_context->SetSecurityToken(password);
21760 Local<String> i = v8_str("i");
21761 Local<String> o = v8_str("o");
21762 Local<String> id = v8_str("id");
21764 CompileRun("function ownfunc() { return { 0: this.id, "
21766 " toString: function() { "
21773 context->Global()->Set(v8_str("func"), foreign_function);
21775 // Sanity check the contexts.
21776 CHECK(i->Equals(foreign_context->Global()->Get(id)));
21777 CHECK(o->Equals(context->Global()->Get(id)));
21779 // Checking local function's receiver.
21780 // Calling function using its call/apply methods.
21781 TestReceiver(o, context->Global(), "ownfunc.call()");
21782 TestReceiver(o, context->Global(), "ownfunc.apply()");
21783 // Making calls through built-in functions.
21784 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
21785 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
21786 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
21787 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
21788 // Calling with environment record as base.
21789 TestReceiver(o, context->Global(), "ownfunc()");
21790 // Calling with no base.
21791 TestReceiver(o, context->Global(), "(1,ownfunc)()");
21793 // Checking foreign function return value.
21794 // Calling function using its call/apply methods.
21795 TestReceiver(i, foreign_context->Global(), "func.call()");
21796 TestReceiver(i, foreign_context->Global(), "func.apply()");
21797 // Calling function using another context's call/apply methods.
21798 TestReceiver(i, foreign_context->Global(),
21799 "Function.prototype.call.call(func)");
21800 TestReceiver(i, foreign_context->Global(),
21801 "Function.prototype.call.apply(func)");
21802 TestReceiver(i, foreign_context->Global(),
21803 "Function.prototype.apply.call(func)");
21804 TestReceiver(i, foreign_context->Global(),
21805 "Function.prototype.apply.apply(func)");
21806 // Making calls through built-in functions.
21807 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
21808 // ToString(func()) is func()[0], i.e., the returned this.id.
21809 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
21810 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
21811 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
21813 // Calling with environment record as base.
21814 TestReceiver(i, foreign_context->Global(), "func()");
21815 // Calling with no base.
21816 TestReceiver(i, foreign_context->Global(), "(1,func)()");
21820 uint8_t callback_fired = 0;
21823 void CallCompletedCallback1() {
21824 v8::base::OS::Print("Firing callback 1.\n");
21825 callback_fired ^= 1; // Toggle first bit.
21829 void CallCompletedCallback2() {
21830 v8::base::OS::Print("Firing callback 2.\n");
21831 callback_fired ^= 2; // Toggle second bit.
21835 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
21836 int32_t level = args[0]->Int32Value();
21839 v8::base::OS::Print("Entering recursion level %d.\n", level);
21841 i::Vector<char> script_vector(script, sizeof(script));
21842 i::SNPrintF(script_vector, "recursion(%d)", level);
21843 CompileRun(script_vector.start());
21844 v8::base::OS::Print("Leaving recursion level %d.\n", level);
21845 CHECK_EQ(0, callback_fired);
21847 v8::base::OS::Print("Recursion ends.\n");
21848 CHECK_EQ(0, callback_fired);
21853 TEST(CallCompletedCallback) {
21855 v8::HandleScope scope(env->GetIsolate());
21856 v8::Handle<v8::FunctionTemplate> recursive_runtime =
21857 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
21858 env->Global()->Set(v8_str("recursion"),
21859 recursive_runtime->GetFunction());
21860 // Adding the same callback a second time has no effect.
21861 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21862 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21863 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
21864 v8::base::OS::Print("--- Script (1) ---\n");
21865 Local<Script> script = v8::Script::Compile(
21866 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
21868 CHECK_EQ(3, callback_fired);
21870 v8::base::OS::Print("\n--- Script (2) ---\n");
21871 callback_fired = 0;
21872 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
21874 CHECK_EQ(2, callback_fired);
21876 v8::base::OS::Print("\n--- Function ---\n");
21877 callback_fired = 0;
21878 Local<Function> recursive_function =
21879 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
21880 v8::Handle<Value> args[] = { v8_num(0) };
21881 recursive_function->Call(env->Global(), 1, args);
21882 CHECK_EQ(2, callback_fired);
21886 void CallCompletedCallbackNoException() {
21887 v8::HandleScope scope(CcTest::isolate());
21888 CompileRun("1+1;");
21892 void CallCompletedCallbackException() {
21893 v8::HandleScope scope(CcTest::isolate());
21894 CompileRun("throw 'second exception';");
21898 TEST(CallCompletedCallbackOneException) {
21900 v8::HandleScope scope(env->GetIsolate());
21901 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
21902 CompileRun("throw 'exception';");
21906 TEST(CallCompletedCallbackTwoExceptions) {
21908 v8::HandleScope scope(env->GetIsolate());
21909 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
21910 CompileRun("throw 'first exception';");
21914 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
21915 v8::HandleScope scope(info.GetIsolate());
21916 CompileRun("ext1Calls++;");
21920 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
21921 v8::HandleScope scope(info.GetIsolate());
21922 CompileRun("ext2Calls++;");
21926 void* g_passed_to_three = NULL;
21929 static void MicrotaskThree(void* data) {
21930 g_passed_to_three = data;
21934 TEST(EnqueueMicrotask) {
21936 v8::HandleScope scope(env->GetIsolate());
21938 "var ext1Calls = 0;"
21939 "var ext2Calls = 0;");
21940 CompileRun("1+1;");
21941 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
21942 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21944 env->GetIsolate()->EnqueueMicrotask(
21945 Function::New(env->GetIsolate(), MicrotaskOne));
21946 CompileRun("1+1;");
21947 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21948 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21950 env->GetIsolate()->EnqueueMicrotask(
21951 Function::New(env->GetIsolate(), MicrotaskOne));
21952 env->GetIsolate()->EnqueueMicrotask(
21953 Function::New(env->GetIsolate(), MicrotaskTwo));
21954 CompileRun("1+1;");
21955 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21956 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21958 env->GetIsolate()->EnqueueMicrotask(
21959 Function::New(env->GetIsolate(), MicrotaskTwo));
21960 CompileRun("1+1;");
21961 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21962 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21964 CompileRun("1+1;");
21965 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21966 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21968 g_passed_to_three = NULL;
21969 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
21970 CompileRun("1+1;");
21971 CHECK_EQ(NULL, g_passed_to_three);
21972 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21973 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21976 env->GetIsolate()->EnqueueMicrotask(
21977 Function::New(env->GetIsolate(), MicrotaskOne));
21978 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
21979 env->GetIsolate()->EnqueueMicrotask(
21980 Function::New(env->GetIsolate(), MicrotaskTwo));
21981 CompileRun("1+1;");
21982 CHECK_EQ(&dummy, g_passed_to_three);
21983 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
21984 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21985 g_passed_to_three = NULL;
21989 static void MicrotaskExceptionOne(
21990 const v8::FunctionCallbackInfo<Value>& info) {
21991 v8::HandleScope scope(info.GetIsolate());
21992 CompileRun("exception1Calls++;");
21993 info.GetIsolate()->ThrowException(
21994 v8::Exception::Error(v8_str("first")));
21998 static void MicrotaskExceptionTwo(
21999 const v8::FunctionCallbackInfo<Value>& info) {
22000 v8::HandleScope scope(info.GetIsolate());
22001 CompileRun("exception2Calls++;");
22002 info.GetIsolate()->ThrowException(
22003 v8::Exception::Error(v8_str("second")));
22007 TEST(RunMicrotasksIgnoresThrownExceptions) {
22009 v8::Isolate* isolate = env->GetIsolate();
22010 v8::HandleScope scope(isolate);
22012 "var exception1Calls = 0;"
22013 "var exception2Calls = 0;");
22014 isolate->EnqueueMicrotask(
22015 Function::New(isolate, MicrotaskExceptionOne));
22016 isolate->EnqueueMicrotask(
22017 Function::New(isolate, MicrotaskExceptionTwo));
22018 TryCatch try_catch;
22019 CompileRun("1+1;");
22020 CHECK(!try_catch.HasCaught());
22021 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
22022 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
22026 TEST(SetAutorunMicrotasks) {
22028 v8::HandleScope scope(env->GetIsolate());
22030 "var ext1Calls = 0;"
22031 "var ext2Calls = 0;");
22032 CompileRun("1+1;");
22033 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
22034 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
22036 env->GetIsolate()->EnqueueMicrotask(
22037 Function::New(env->GetIsolate(), MicrotaskOne));
22038 CompileRun("1+1;");
22039 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
22040 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
22042 env->GetIsolate()->SetAutorunMicrotasks(false);
22043 env->GetIsolate()->EnqueueMicrotask(
22044 Function::New(env->GetIsolate(), MicrotaskOne));
22045 env->GetIsolate()->EnqueueMicrotask(
22046 Function::New(env->GetIsolate(), MicrotaskTwo));
22047 CompileRun("1+1;");
22048 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
22049 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
22051 env->GetIsolate()->RunMicrotasks();
22052 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22053 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
22055 env->GetIsolate()->EnqueueMicrotask(
22056 Function::New(env->GetIsolate(), MicrotaskTwo));
22057 CompileRun("1+1;");
22058 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22059 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
22061 env->GetIsolate()->RunMicrotasks();
22062 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22063 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
22065 env->GetIsolate()->SetAutorunMicrotasks(true);
22066 env->GetIsolate()->EnqueueMicrotask(
22067 Function::New(env->GetIsolate(), MicrotaskTwo));
22068 CompileRun("1+1;");
22069 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22070 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
22072 env->GetIsolate()->EnqueueMicrotask(
22073 Function::New(env->GetIsolate(), MicrotaskTwo));
22075 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
22076 CompileRun("1+1;");
22077 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22078 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
22081 CompileRun("1+1;");
22082 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
22083 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
22087 TEST(RunMicrotasksWithoutEnteringContext) {
22088 v8::Isolate* isolate = CcTest::isolate();
22089 HandleScope handle_scope(isolate);
22090 isolate->SetAutorunMicrotasks(false);
22091 Handle<Context> context = Context::New(isolate);
22093 Context::Scope context_scope(context);
22094 CompileRun("var ext1Calls = 0;");
22095 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
22097 isolate->RunMicrotasks();
22099 Context::Scope context_scope(context);
22100 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
22102 isolate->SetAutorunMicrotasks(true);
22106 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
22107 v8::DebugEvent event = event_details.GetEvent();
22108 if (event != v8::Break) return;
22109 Handle<Object> exec_state = event_details.GetExecutionState();
22110 Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
22111 CompileRun("function f(id) { new FrameDetails(id, 0); }");
22112 Handle<Function> fun =
22113 Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
22114 fun->Call(CcTest::global(), 1, &break_id);
22118 TEST(Regress385349) {
22119 i::FLAG_allow_natives_syntax = true;
22120 v8::Isolate* isolate = CcTest::isolate();
22121 HandleScope handle_scope(isolate);
22122 isolate->SetAutorunMicrotasks(false);
22123 Handle<Context> context = Context::New(isolate);
22124 v8::Debug::SetDebugEventListener(DebugEventInObserver);
22126 Context::Scope context_scope(context);
22127 CompileRun("var obj = {};"
22128 "Object.observe(obj, function(changes) { debugger; });"
22131 isolate->RunMicrotasks();
22132 isolate->SetAutorunMicrotasks(true);
22133 v8::Debug::SetDebugEventListener(NULL);
22137 #ifdef ENABLE_DISASSEMBLER
22138 static int probes_counter = 0;
22139 static int misses_counter = 0;
22140 static int updates_counter = 0;
22143 static int* LookupCounter(const char* name) {
22144 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
22145 return &probes_counter;
22146 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
22147 return &misses_counter;
22148 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
22149 return &updates_counter;
22155 static const char* kMegamorphicTestProgram =
22156 "function ClassA() { };"
22157 "function ClassB() { };"
22158 "ClassA.prototype.foo = function() { };"
22159 "ClassB.prototype.foo = function() { };"
22160 "function fooify(obj) { obj.foo(); };"
22161 "var a = new ClassA();"
22162 "var b = new ClassB();"
22163 "for (var i = 0; i < 10000; i++) {"
22170 static void StubCacheHelper(bool primary) {
22171 #ifdef ENABLE_DISASSEMBLER
22172 i::FLAG_native_code_counters = true;
22174 i::FLAG_test_primary_stub_cache = true;
22176 i::FLAG_test_secondary_stub_cache = true;
22178 i::FLAG_crankshaft = false;
22180 env->GetIsolate()->SetCounterFunction(LookupCounter);
22181 v8::HandleScope scope(env->GetIsolate());
22182 int initial_probes = probes_counter;
22183 int initial_misses = misses_counter;
22184 int initial_updates = updates_counter;
22185 CompileRun(kMegamorphicTestProgram);
22186 int probes = probes_counter - initial_probes;
22187 int misses = misses_counter - initial_misses;
22188 int updates = updates_counter - initial_updates;
22189 CHECK_LT(updates, 10);
22190 CHECK_LT(misses, 10);
22191 // TODO(verwaest): Update this test to overflow the degree of polymorphism
22192 // before megamorphism. The number of probes will only work once we teach the
22193 // serializer to embed references to counters in the stubs, given that the
22194 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
22195 CHECK_GE(probes, 0);
22200 TEST(SecondaryStubCache) {
22201 StubCacheHelper(true);
22205 TEST(PrimaryStubCache) {
22206 StubCacheHelper(false);
22211 static int cow_arrays_created_runtime = 0;
22214 static int* LookupCounterCOWArrays(const char* name) {
22215 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
22216 return &cow_arrays_created_runtime;
22223 TEST(CheckCOWArraysCreatedRuntimeCounter) {
22225 i::FLAG_native_code_counters = true;
22227 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
22228 v8::HandleScope scope(env->GetIsolate());
22229 int initial_cow_arrays = cow_arrays_created_runtime;
22230 CompileRun("var o = [1, 2, 3];");
22231 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
22232 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
22233 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
22234 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
22235 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
22240 TEST(StaticGetters) {
22241 LocalContext context;
22242 i::Factory* factory = CcTest::i_isolate()->factory();
22243 v8::Isolate* isolate = CcTest::isolate();
22244 v8::HandleScope scope(isolate);
22245 i::Handle<i::Object> undefined_value = factory->undefined_value();
22246 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
22247 i::Handle<i::Object> null_value = factory->null_value();
22248 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
22249 i::Handle<i::Object> true_value = factory->true_value();
22250 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
22251 i::Handle<i::Object> false_value = factory->false_value();
22252 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
22256 UNINITIALIZED_TEST(IsolateEmbedderData) {
22257 CcTest::DisableAutomaticDispose();
22258 v8::Isolate* isolate = v8::Isolate::New();
22260 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
22261 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22262 CHECK_EQ(NULL, isolate->GetData(slot));
22263 CHECK_EQ(NULL, i_isolate->GetData(slot));
22265 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22266 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
22267 isolate->SetData(slot, data);
22269 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22270 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
22271 CHECK_EQ(data, isolate->GetData(slot));
22272 CHECK_EQ(data, i_isolate->GetData(slot));
22274 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22275 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
22276 isolate->SetData(slot, data);
22278 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
22279 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
22280 CHECK_EQ(data, isolate->GetData(slot));
22281 CHECK_EQ(data, i_isolate->GetData(slot));
22284 isolate->Dispose();
22288 TEST(StringEmpty) {
22289 LocalContext context;
22290 i::Factory* factory = CcTest::i_isolate()->factory();
22291 v8::Isolate* isolate = CcTest::isolate();
22292 v8::HandleScope scope(isolate);
22293 i::Handle<i::Object> empty_string = factory->empty_string();
22294 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
22298 static int instance_checked_getter_count = 0;
22299 static void InstanceCheckedGetter(
22300 Local<String> name,
22301 const v8::PropertyCallbackInfo<v8::Value>& info) {
22302 CHECK_EQ(name, v8_str("foo"));
22303 instance_checked_getter_count++;
22304 info.GetReturnValue().Set(v8_num(11));
22308 static int instance_checked_setter_count = 0;
22309 static void InstanceCheckedSetter(Local<String> name,
22310 Local<Value> value,
22311 const v8::PropertyCallbackInfo<void>& info) {
22312 CHECK_EQ(name, v8_str("foo"));
22313 CHECK_EQ(value, v8_num(23));
22314 instance_checked_setter_count++;
22318 static void CheckInstanceCheckedResult(int getters, int setters,
22319 bool expects_callbacks,
22320 TryCatch* try_catch) {
22321 if (expects_callbacks) {
22322 CHECK(!try_catch->HasCaught());
22323 CHECK_EQ(getters, instance_checked_getter_count);
22324 CHECK_EQ(setters, instance_checked_setter_count);
22326 CHECK(try_catch->HasCaught());
22327 CHECK_EQ(0, instance_checked_getter_count);
22328 CHECK_EQ(0, instance_checked_setter_count);
22330 try_catch->Reset();
22334 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
22335 instance_checked_getter_count = 0;
22336 instance_checked_setter_count = 0;
22337 TryCatch try_catch;
22339 // Test path through generic runtime code.
22340 CompileRun("obj.foo");
22341 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
22342 CompileRun("obj.foo = 23");
22343 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
22345 // Test path through generated LoadIC and StoredIC.
22346 CompileRun("function test_get(o) { o.foo; }"
22348 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
22349 CompileRun("test_get(obj);");
22350 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
22351 CompileRun("test_get(obj);");
22352 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
22353 CompileRun("function test_set(o) { o.foo = 23; }"
22355 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
22356 CompileRun("test_set(obj);");
22357 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
22358 CompileRun("test_set(obj);");
22359 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
22361 // Test path through optimized code.
22362 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
22364 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
22365 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
22367 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
22369 // Cleanup so that closures start out fresh in next check.
22370 CompileRun("%DeoptimizeFunction(test_get);"
22371 "%ClearFunctionTypeFeedback(test_get);"
22372 "%DeoptimizeFunction(test_set);"
22373 "%ClearFunctionTypeFeedback(test_set);");
22377 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
22378 v8::internal::FLAG_allow_natives_syntax = true;
22379 LocalContext context;
22380 v8::HandleScope scope(context->GetIsolate());
22382 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22383 Local<ObjectTemplate> inst = templ->InstanceTemplate();
22384 inst->SetAccessor(v8_str("foo"),
22385 InstanceCheckedGetter, InstanceCheckedSetter,
22389 v8::AccessorSignature::New(context->GetIsolate(), templ));
22390 context->Global()->Set(v8_str("f"), templ->GetFunction());
22392 printf("Testing positive ...\n");
22393 CompileRun("var obj = new f();");
22394 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22395 CheckInstanceCheckedAccessors(true);
22397 printf("Testing negative ...\n");
22398 CompileRun("var obj = {};"
22399 "obj.__proto__ = new f();");
22400 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22401 CheckInstanceCheckedAccessors(false);
22405 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
22406 v8::internal::FLAG_allow_natives_syntax = true;
22407 LocalContext context;
22408 v8::HandleScope scope(context->GetIsolate());
22410 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22411 Local<ObjectTemplate> inst = templ->InstanceTemplate();
22412 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22413 inst->SetAccessor(v8_str("foo"),
22414 InstanceCheckedGetter, InstanceCheckedSetter,
22418 v8::AccessorSignature::New(context->GetIsolate(), templ));
22419 context->Global()->Set(v8_str("f"), templ->GetFunction());
22421 printf("Testing positive ...\n");
22422 CompileRun("var obj = new f();");
22423 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22424 CheckInstanceCheckedAccessors(true);
22426 printf("Testing negative ...\n");
22427 CompileRun("var obj = {};"
22428 "obj.__proto__ = new f();");
22429 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22430 CheckInstanceCheckedAccessors(false);
22434 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
22435 v8::internal::FLAG_allow_natives_syntax = true;
22436 LocalContext context;
22437 v8::HandleScope scope(context->GetIsolate());
22439 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22440 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
22441 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
22442 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
22444 v8::AccessorSignature::New(context->GetIsolate(), templ));
22445 context->Global()->Set(v8_str("f"), templ->GetFunction());
22447 printf("Testing positive ...\n");
22448 CompileRun("var obj = new f();");
22449 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22450 CheckInstanceCheckedAccessors(true);
22452 printf("Testing negative ...\n");
22453 CompileRun("var obj = {};"
22454 "obj.__proto__ = new f();");
22455 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22456 CheckInstanceCheckedAccessors(false);
22458 printf("Testing positive with modified prototype chain ...\n");
22459 CompileRun("var obj = new f();"
22461 "pro.__proto__ = obj.__proto__;"
22462 "obj.__proto__ = pro;");
22463 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22464 CheckInstanceCheckedAccessors(true);
22468 TEST(TryFinallyMessage) {
22469 LocalContext context;
22470 v8::HandleScope scope(context->GetIsolate());
22472 // Test that the original error message is not lost if there is a
22473 // recursive call into Javascript is done in the finally block, e.g. to
22474 // initialize an IC. (crbug.com/129171)
22475 TryCatch try_catch;
22476 const char* trigger_ic =
22478 " throw new Error('test'); \n"
22481 " x++; \n" // Trigger an IC initialization here.
22483 CompileRun(trigger_ic);
22484 CHECK(try_catch.HasCaught());
22485 Local<Message> message = try_catch.Message();
22486 CHECK(!message.IsEmpty());
22487 CHECK_EQ(2, message->GetLineNumber());
22491 // Test that the original exception message is indeed overwritten if
22492 // a new error is thrown in the finally block.
22493 TryCatch try_catch;
22494 const char* throw_again =
22496 " throw new Error('test'); \n"
22500 " throw new Error('again'); \n" // This is the new uncaught error.
22502 CompileRun(throw_again);
22503 CHECK(try_catch.HasCaught());
22504 Local<Message> message = try_catch.Message();
22505 CHECK(!message.IsEmpty());
22506 CHECK_EQ(6, message->GetLineNumber());
22511 static void Helper137002(bool do_store,
22513 bool remove_accessor,
22514 bool interceptor) {
22515 LocalContext context;
22516 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
22518 templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
22519 FooSetInterceptor));
22521 templ->SetAccessor(v8_str("foo"),
22522 GetterWhichReturns42,
22523 SetterWhichSetsYOnThisTo23);
22525 context->Global()->Set(v8_str("obj"), templ->NewInstance());
22527 // Turn monomorphic on slow object with native accessor, then turn
22528 // polymorphic, finally optimize to create negative lookup and fail.
22529 CompileRun(do_store ?
22530 "function f(x) { x.foo = void 0; }" :
22531 "function f(x) { return x.foo; }");
22532 CompileRun("obj.y = void 0;");
22533 if (!interceptor) {
22534 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
22536 CompileRun("obj.__proto__ = null;"
22537 "f(obj); f(obj); f(obj);");
22539 CompileRun("f({});");
22541 CompileRun("obj.y = void 0;"
22542 "%OptimizeFunctionOnNextCall(f);");
22543 if (remove_accessor) {
22544 CompileRun("delete obj.foo;");
22546 CompileRun("var result = f(obj);");
22548 CompileRun("result = obj.y;");
22550 if (remove_accessor && !interceptor) {
22551 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
22553 CHECK_EQ(do_store ? 23 : 42,
22554 context->Global()->Get(v8_str("result"))->Int32Value());
22559 THREADED_TEST(Regress137002a) {
22560 i::FLAG_allow_natives_syntax = true;
22561 i::FLAG_compilation_cache = false;
22562 v8::HandleScope scope(CcTest::isolate());
22563 for (int i = 0; i < 16; i++) {
22564 Helper137002(i & 8, i & 4, i & 2, i & 1);
22569 THREADED_TEST(Regress137002b) {
22570 i::FLAG_allow_natives_syntax = true;
22571 LocalContext context;
22572 v8::Isolate* isolate = context->GetIsolate();
22573 v8::HandleScope scope(isolate);
22574 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22575 templ->SetAccessor(v8_str("foo"),
22576 GetterWhichReturns42,
22577 SetterWhichSetsYOnThisTo23);
22578 context->Global()->Set(v8_str("obj"), templ->NewInstance());
22580 // Turn monomorphic on slow object with native accessor, then just
22581 // delete the property and fail.
22582 CompileRun("function load(x) { return x.foo; }"
22583 "function store(x) { x.foo = void 0; }"
22584 "function keyed_load(x, key) { return x[key]; }"
22585 // Second version of function has a different source (add void 0)
22586 // so that it does not share code with the first version. This
22587 // ensures that the ICs are monomorphic.
22588 "function load2(x) { void 0; return x.foo; }"
22589 "function store2(x) { void 0; x.foo = void 0; }"
22590 "function keyed_load2(x, key) { void 0; return x[key]; }"
22593 "obj.__proto__ = null;"
22595 "subobj.y = void 0;"
22596 "subobj.__proto__ = obj;"
22597 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22599 // Make the ICs monomorphic.
22600 "load(obj); load(obj);"
22601 "load2(subobj); load2(subobj);"
22602 "store(obj); store(obj);"
22603 "store2(subobj); store2(subobj);"
22604 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
22605 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
22607 // Actually test the shiny new ICs and better not crash. This
22608 // serves as a regression test for issue 142088 as well.
22613 "keyed_load(obj, 'foo');"
22614 "keyed_load2(subobj, 'foo');"
22616 // Delete the accessor. It better not be called any more now.
22619 "subobj.y = void 0;"
22621 "var load_result = load(obj);"
22622 "var load_result2 = load2(subobj);"
22623 "var keyed_load_result = keyed_load(obj, 'foo');"
22624 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
22627 "var y_from_obj = obj.y;"
22628 "var y_from_subobj = subobj.y;");
22629 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
22630 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
22631 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
22632 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
22633 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
22634 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
22638 THREADED_TEST(Regress142088) {
22639 i::FLAG_allow_natives_syntax = true;
22640 LocalContext context;
22641 v8::Isolate* isolate = context->GetIsolate();
22642 v8::HandleScope scope(isolate);
22643 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22644 templ->SetAccessor(v8_str("foo"),
22645 GetterWhichReturns42,
22646 SetterWhichSetsYOnThisTo23);
22647 context->Global()->Set(v8_str("obj"), templ->NewInstance());
22649 CompileRun("function load(x) { return x.foo; }"
22650 "var o = Object.create(obj);"
22651 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22652 "load(o); load(o); load(o); load(o);");
22656 THREADED_TEST(Regress3337) {
22657 LocalContext context;
22658 v8::Isolate* isolate = context->GetIsolate();
22659 v8::HandleScope scope(isolate);
22660 Local<v8::Object> o1 = Object::New(isolate);
22661 Local<v8::Object> o2 = Object::New(isolate);
22662 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
22663 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
22664 CHECK(io1->map() == io2->map());
22665 o1->SetIndexedPropertiesToExternalArrayData(
22666 NULL, v8::kExternalUint32Array, 0);
22667 o2->SetIndexedPropertiesToExternalArrayData(
22668 NULL, v8::kExternalUint32Array, 0);
22669 CHECK(io1->map() == io2->map());
22673 THREADED_TEST(Regress137496) {
22674 i::FLAG_expose_gc = true;
22675 LocalContext context;
22676 v8::HandleScope scope(context->GetIsolate());
22678 // Compile a try-finally clause where the finally block causes a GC
22679 // while there still is a message pending for external reporting.
22680 TryCatch try_catch;
22681 try_catch.SetVerbose(true);
22682 CompileRun("try { throw new Error(); } finally { gc(); }");
22683 CHECK(try_catch.HasCaught());
22687 THREADED_TEST(Regress149912) {
22688 LocalContext context;
22689 v8::HandleScope scope(context->GetIsolate());
22690 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22691 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22692 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
22693 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
22697 THREADED_TEST(Regress157124) {
22698 LocalContext context;
22699 v8::Isolate* isolate = context->GetIsolate();
22700 v8::HandleScope scope(isolate);
22701 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22702 Local<Object> obj = templ->NewInstance();
22703 obj->GetIdentityHash();
22704 obj->DeleteHiddenValue(v8_str("Bug"));
22708 THREADED_TEST(Regress2535) {
22709 LocalContext context;
22710 v8::HandleScope scope(context->GetIsolate());
22711 Local<Value> set_value = CompileRun("new Set();");
22712 Local<Object> set_object(Local<Object>::Cast(set_value));
22713 CHECK_EQ(0, set_object->InternalFieldCount());
22714 Local<Value> map_value = CompileRun("new Map();");
22715 Local<Object> map_object(Local<Object>::Cast(map_value));
22716 CHECK_EQ(0, map_object->InternalFieldCount());
22720 THREADED_TEST(Regress2746) {
22721 LocalContext context;
22722 v8::Isolate* isolate = context->GetIsolate();
22723 v8::HandleScope scope(isolate);
22724 Local<Object> obj = Object::New(isolate);
22725 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
22726 obj->SetHiddenValue(key, v8::Undefined(isolate));
22727 Local<Value> value = obj->GetHiddenValue(key);
22728 CHECK(!value.IsEmpty());
22729 CHECK(value->IsUndefined());
22733 THREADED_TEST(Regress260106) {
22734 LocalContext context;
22735 v8::Isolate* isolate = context->GetIsolate();
22736 v8::HandleScope scope(isolate);
22737 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
22739 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
22740 Local<Function> function = templ->GetFunction();
22741 CHECK(!function.IsEmpty());
22742 CHECK(function->IsFunction());
22746 THREADED_TEST(JSONParseObject) {
22747 LocalContext context;
22748 HandleScope scope(context->GetIsolate());
22749 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
22750 Handle<Object> global = context->Global();
22751 global->Set(v8_str("obj"), obj);
22752 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
22756 THREADED_TEST(JSONParseNumber) {
22757 LocalContext context;
22758 HandleScope scope(context->GetIsolate());
22759 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
22760 Handle<Object> global = context->Global();
22761 global->Set(v8_str("obj"), obj);
22762 ExpectString("JSON.stringify(obj)", "42");
22766 #if V8_OS_POSIX && !V8_OS_NACL
22767 class ThreadInterruptTest {
22769 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
22770 ~ThreadInterruptTest() {}
22773 InterruptThread i_thread(this);
22777 CHECK_EQ(kExpectedValue, sem_value_);
22781 static const int kExpectedValue = 1;
22783 class InterruptThread : public v8::base::Thread {
22785 explicit InterruptThread(ThreadInterruptTest* test)
22786 : Thread(Options("InterruptThread")), test_(test) {}
22788 virtual void Run() {
22789 struct sigaction action;
22791 // Ensure that we'll enter waiting condition
22792 v8::base::OS::Sleep(100);
22794 // Setup signal handler
22795 memset(&action, 0, sizeof(action));
22796 action.sa_handler = SignalHandler;
22797 sigaction(SIGCHLD, &action, NULL);
22800 kill(getpid(), SIGCHLD);
22802 // Ensure that if wait has returned because of error
22803 v8::base::OS::Sleep(100);
22805 // Set value and signal semaphore
22806 test_->sem_value_ = 1;
22807 test_->sem_.Signal();
22810 static void SignalHandler(int signal) {
22814 ThreadInterruptTest* test_;
22817 v8::base::Semaphore sem_;
22818 volatile int sem_value_;
22822 THREADED_TEST(SemaphoreInterruption) {
22823 ThreadInterruptTest().RunTest();
22827 #endif // V8_OS_POSIX
22830 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
22832 v8::AccessType type,
22833 Local<Value> data) {
22834 i::PrintF("Named access blocked.\n");
22839 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
22841 v8::AccessType type,
22842 Local<Value> data) {
22843 i::PrintF("Indexed access blocked.\n");
22848 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22853 TEST(JSONStringifyAccessCheck) {
22854 v8::V8::Initialize();
22855 v8::Isolate* isolate = CcTest::isolate();
22856 v8::HandleScope scope(isolate);
22858 // Create an ObjectTemplate for global objects and install access
22859 // check callbacks that will block access.
22860 v8::Handle<v8::ObjectTemplate> global_template =
22861 v8::ObjectTemplate::New(isolate);
22862 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
22863 IndexAccessAlwaysBlocked);
22865 // Create a context and set an x property on it's global object.
22866 LocalContext context0(NULL, global_template);
22867 v8::Handle<v8::Object> global0 = context0->Global();
22868 global0->Set(v8_str("x"), v8_num(42));
22869 ExpectString("JSON.stringify(this)", "{\"x\":42}");
22871 for (int i = 0; i < 2; i++) {
22873 // Install a toJSON function on the second run.
22874 v8::Handle<v8::FunctionTemplate> toJSON =
22875 v8::FunctionTemplate::New(isolate, UnreachableCallback);
22877 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
22879 // Create a context with a different security token so that the
22880 // failed access check callback will be called on each access.
22881 LocalContext context1(NULL, global_template);
22882 context1->Global()->Set(v8_str("other"), global0);
22884 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
22885 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
22886 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
22888 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
22889 array->Set(0, v8_str("a"));
22890 array->Set(1, v8_str("b"));
22891 context1->Global()->Set(v8_str("array"), array);
22892 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
22893 array->TurnOnAccessCheck();
22894 CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
22895 CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
22896 CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
22901 bool access_check_fail_thrown = false;
22902 bool catch_callback_called = false;
22905 // Failed access check callback that performs a GC on each invocation.
22906 void FailedAccessCheckThrows(Local<v8::Object> target,
22907 v8::AccessType type,
22908 Local<v8::Value> data) {
22909 access_check_fail_thrown = true;
22910 i::PrintF("Access check failed. Error thrown.\n");
22911 CcTest::isolate()->ThrowException(
22912 v8::Exception::Error(v8_str("cross context")));
22916 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22917 for (int i = 0; i < args.Length(); i++) {
22918 i::PrintF("%s\n", *String::Utf8Value(args[i]));
22920 catch_callback_called = true;
22924 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22925 args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
22926 args[1]->ToString(args.GetIsolate()));
22930 void CheckCorrectThrow(const char* script) {
22931 // Test that the script, when wrapped into a try-catch, triggers the catch
22932 // clause due to failed access check throwing an exception.
22933 // The subsequent try-catch should run without any exception.
22934 access_check_fail_thrown = false;
22935 catch_callback_called = false;
22936 i::ScopedVector<char> source(1024);
22937 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
22938 CompileRun(source.start());
22939 CHECK(access_check_fail_thrown);
22940 CHECK(catch_callback_called);
22942 access_check_fail_thrown = false;
22943 catch_callback_called = false;
22944 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
22945 CHECK(!access_check_fail_thrown);
22946 CHECK(!catch_callback_called);
22950 TEST(AccessCheckThrows) {
22951 i::FLAG_allow_natives_syntax = true;
22952 v8::V8::Initialize();
22953 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
22954 v8::Isolate* isolate = CcTest::isolate();
22955 v8::HandleScope scope(isolate);
22957 // Create an ObjectTemplate for global objects and install access
22958 // check callbacks that will block access.
22959 v8::Handle<v8::ObjectTemplate> global_template =
22960 v8::ObjectTemplate::New(isolate);
22961 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
22962 IndexAccessAlwaysBlocked);
22964 // Create a context and set an x property on it's global object.
22965 LocalContext context0(NULL, global_template);
22966 v8::Handle<v8::Object> global0 = context0->Global();
22968 // Create a context with a different security token so that the
22969 // failed access check callback will be called on each access.
22970 LocalContext context1(NULL, global_template);
22971 context1->Global()->Set(v8_str("other"), global0);
22973 v8::Handle<v8::FunctionTemplate> catcher_fun =
22974 v8::FunctionTemplate::New(isolate, CatcherCallback);
22975 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
22977 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
22978 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
22979 context1->Global()->Set(v8_str("has_own_property"),
22980 has_own_property_fun->GetFunction());
22982 { v8::TryCatch try_catch;
22983 access_check_fail_thrown = false;
22984 CompileRun("other.x;");
22985 CHECK(access_check_fail_thrown);
22986 CHECK(try_catch.HasCaught());
22989 CheckCorrectThrow("other.x");
22990 CheckCorrectThrow("other[1]");
22991 CheckCorrectThrow("JSON.stringify(other)");
22992 CheckCorrectThrow("has_own_property(other, 'x')");
22993 CheckCorrectThrow("%GetProperty(other, 'x')");
22994 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
22995 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
22996 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
22997 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
22998 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
22999 CheckCorrectThrow("%HasProperty(other, 'x')");
23000 CheckCorrectThrow("%HasElement(other, 1)");
23001 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
23002 CheckCorrectThrow("%GetPropertyNames(other)");
23003 // PROPERTY_ATTRIBUTES_NONE = 0
23004 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
23005 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
23006 "other, 'x', null, null, 1)");
23008 // Reset the failed access check callback so it does not influence
23009 // the other tests.
23010 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
23014 THREADED_TEST(Regress256330) {
23015 i::FLAG_allow_natives_syntax = true;
23016 LocalContext context;
23017 v8::HandleScope scope(context->GetIsolate());
23018 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
23019 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
23020 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
23021 CompileRun("\"use strict\"; var o = new Bug;"
23022 "function f(o) { o.x = 10; };"
23023 "f(o); f(o); f(o);"
23024 "%OptimizeFunctionOnNextCall(f);"
23026 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
23030 THREADED_TEST(CrankshaftInterceptorSetter) {
23031 i::FLAG_allow_natives_syntax = true;
23032 v8::HandleScope scope(CcTest::isolate());
23033 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23034 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23036 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23037 CompileRun("var obj = new Obj;"
23038 // Initialize fields to avoid transitions later.
23040 "obj.accessor_age = 42;"
23041 "function setter(i) { this.accessor_age = i; };"
23042 "function getter() { return this.accessor_age; };"
23043 "function setAge(i) { obj.age = i; };"
23044 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
23048 "%OptimizeFunctionOnNextCall(setAge);"
23050 // All stores went through the interceptor.
23051 ExpectInt32("obj.interceptor_age", 4);
23052 ExpectInt32("obj.accessor_age", 42);
23056 THREADED_TEST(CrankshaftInterceptorGetter) {
23057 i::FLAG_allow_natives_syntax = true;
23058 v8::HandleScope scope(CcTest::isolate());
23059 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23060 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23062 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23063 CompileRun("var obj = new Obj;"
23064 // Initialize fields to avoid transitions later.
23066 "obj.accessor_age = 42;"
23067 "function getter() { return this.accessor_age; };"
23068 "function getAge() { return obj.interceptor_age; };"
23069 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
23073 "%OptimizeFunctionOnNextCall(getAge);");
23074 // Access through interceptor.
23075 ExpectInt32("getAge()", 1);
23079 THREADED_TEST(CrankshaftInterceptorFieldRead) {
23080 i::FLAG_allow_natives_syntax = true;
23081 v8::HandleScope scope(CcTest::isolate());
23082 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23083 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23085 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23086 CompileRun("var obj = new Obj;"
23087 "obj.__proto__.interceptor_age = 42;"
23089 "function getAge() { return obj.interceptor_age; };");
23090 ExpectInt32("getAge();", 100);
23091 ExpectInt32("getAge();", 100);
23092 ExpectInt32("getAge();", 100);
23093 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
23094 // Access through interceptor.
23095 ExpectInt32("getAge();", 100);
23099 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
23100 i::FLAG_allow_natives_syntax = true;
23101 v8::HandleScope scope(CcTest::isolate());
23102 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
23103 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
23105 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
23106 CompileRun("var obj = new Obj;"
23107 "obj.age = 100000;"
23108 "function setAge(i) { obj.age = i };"
23112 "%OptimizeFunctionOnNextCall(setAge);"
23114 ExpectInt32("obj.age", 100000);
23115 ExpectInt32("obj.interceptor_age", 103);
23119 class RequestInterruptTestBase {
23121 RequestInterruptTestBase()
23123 isolate_(env_->GetIsolate()),
23126 should_continue_(true) {
23129 virtual ~RequestInterruptTestBase() { }
23131 virtual void StartInterruptThread() = 0;
23133 virtual void TestBody() = 0;
23136 StartInterruptThread();
23138 v8::HandleScope handle_scope(isolate_);
23142 // Verify we arrived here because interruptor was called
23143 // not due to a bug causing us to exit the loop too early.
23144 CHECK(!should_continue());
23147 void WakeUpInterruptor() {
23151 bool should_continue() const { return should_continue_; }
23153 bool ShouldContinue() {
23155 if (--warmup_ == 0) {
23156 WakeUpInterruptor();
23160 return should_continue_;
23163 static void ShouldContinueCallback(
23164 const v8::FunctionCallbackInfo<Value>& info) {
23165 RequestInterruptTestBase* test =
23166 reinterpret_cast<RequestInterruptTestBase*>(
23167 info.Data().As<v8::External>()->Value());
23168 info.GetReturnValue().Set(test->ShouldContinue());
23172 v8::Isolate* isolate_;
23173 v8::base::Semaphore sem_;
23175 bool should_continue_;
23179 class RequestInterruptTestBaseWithSimpleInterrupt
23180 : public RequestInterruptTestBase {
23182 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
23184 virtual void StartInterruptThread() {
23189 class InterruptThread : public v8::base::Thread {
23191 explicit InterruptThread(RequestInterruptTestBase* test)
23192 : Thread(Options("RequestInterruptTest")), test_(test) {}
23194 virtual void Run() {
23195 test_->sem_.Wait();
23196 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23199 static void OnInterrupt(v8::Isolate* isolate, void* data) {
23200 reinterpret_cast<RequestInterruptTestBase*>(data)->
23201 should_continue_ = false;
23205 RequestInterruptTestBase* test_;
23208 InterruptThread i_thread;
23212 class RequestInterruptTestWithFunctionCall
23213 : public RequestInterruptTestBaseWithSimpleInterrupt {
23215 virtual void TestBody() {
23216 Local<Function> func = Function::New(
23217 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
23218 env_->Global()->Set(v8_str("ShouldContinue"), func);
23220 CompileRun("while (ShouldContinue()) { }");
23225 class RequestInterruptTestWithMethodCall
23226 : public RequestInterruptTestBaseWithSimpleInterrupt {
23228 virtual void TestBody() {
23229 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23230 v8::Local<v8::Template> proto = t->PrototypeTemplate();
23231 proto->Set(v8_str("shouldContinue"), Function::New(
23232 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23233 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23235 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23240 class RequestInterruptTestWithAccessor
23241 : public RequestInterruptTestBaseWithSimpleInterrupt {
23243 virtual void TestBody() {
23244 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23245 v8::Local<v8::Template> proto = t->PrototypeTemplate();
23246 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
23247 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23248 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23250 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23255 class RequestInterruptTestWithNativeAccessor
23256 : public RequestInterruptTestBaseWithSimpleInterrupt {
23258 virtual void TestBody() {
23259 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23260 t->InstanceTemplate()->SetNativeDataProperty(
23261 v8_str("shouldContinue"),
23262 &ShouldContinueNativeGetter,
23264 v8::External::New(isolate_, this));
23265 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23267 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
23271 static void ShouldContinueNativeGetter(
23272 Local<String> property,
23273 const v8::PropertyCallbackInfo<v8::Value>& info) {
23274 RequestInterruptTestBase* test =
23275 reinterpret_cast<RequestInterruptTestBase*>(
23276 info.Data().As<v8::External>()->Value());
23277 info.GetReturnValue().Set(test->ShouldContinue());
23282 class RequestInterruptTestWithMethodCallAndInterceptor
23283 : public RequestInterruptTestBaseWithSimpleInterrupt {
23285 virtual void TestBody() {
23286 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
23287 v8::Local<v8::Template> proto = t->PrototypeTemplate();
23288 proto->Set(v8_str("shouldContinue"), Function::New(
23289 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
23290 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
23291 instance_template->SetHandler(
23292 v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
23294 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
23296 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
23300 static void EmptyInterceptor(
23301 Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
23305 class RequestInterruptTestWithMathAbs
23306 : public RequestInterruptTestBaseWithSimpleInterrupt {
23308 virtual void TestBody() {
23309 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
23311 WakeUpInterruptorCallback,
23312 v8::External::New(isolate_, this)));
23314 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
23316 ShouldContinueCallback,
23317 v8::External::New(isolate_, this)));
23319 i::FLAG_allow_natives_syntax = true;
23320 CompileRun("function loopish(o) {"
23322 " while (o.abs(1) > 0) {"
23323 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
23325 " if (--pre === 0) WakeUpInterruptor(o === Math);"
23330 "var obj = {abs: function () { return i-- }, x: null};"
23333 "%OptimizeFunctionOnNextCall(loopish);"
23336 i::FLAG_allow_natives_syntax = false;
23340 static void WakeUpInterruptorCallback(
23341 const v8::FunctionCallbackInfo<Value>& info) {
23342 if (!info[0]->BooleanValue()) return;
23344 RequestInterruptTestBase* test =
23345 reinterpret_cast<RequestInterruptTestBase*>(
23346 info.Data().As<v8::External>()->Value());
23347 test->WakeUpInterruptor();
23350 static void ShouldContinueCallback(
23351 const v8::FunctionCallbackInfo<Value>& info) {
23352 RequestInterruptTestBase* test =
23353 reinterpret_cast<RequestInterruptTestBase*>(
23354 info.Data().As<v8::External>()->Value());
23355 info.GetReturnValue().Set(test->should_continue());
23360 TEST(RequestInterruptTestWithFunctionCall) {
23361 RequestInterruptTestWithFunctionCall().RunTest();
23365 TEST(RequestInterruptTestWithMethodCall) {
23366 RequestInterruptTestWithMethodCall().RunTest();
23370 TEST(RequestInterruptTestWithAccessor) {
23371 RequestInterruptTestWithAccessor().RunTest();
23375 TEST(RequestInterruptTestWithNativeAccessor) {
23376 RequestInterruptTestWithNativeAccessor().RunTest();
23380 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
23381 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
23385 TEST(RequestInterruptTestWithMathAbs) {
23386 RequestInterruptTestWithMathAbs().RunTest();
23390 class RequestMultipleInterrupts : public RequestInterruptTestBase {
23392 RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
23394 virtual void StartInterruptThread() {
23398 virtual void TestBody() {
23399 Local<Function> func = Function::New(
23400 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
23401 env_->Global()->Set(v8_str("ShouldContinue"), func);
23403 CompileRun("while (ShouldContinue()) { }");
23407 class InterruptThread : public v8::base::Thread {
23409 enum { NUM_INTERRUPTS = 10 };
23410 explicit InterruptThread(RequestMultipleInterrupts* test)
23411 : Thread(Options("RequestInterruptTest")), test_(test) {}
23413 virtual void Run() {
23414 test_->sem_.Wait();
23415 for (int i = 0; i < NUM_INTERRUPTS; i++) {
23416 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23420 static void OnInterrupt(v8::Isolate* isolate, void* data) {
23421 RequestMultipleInterrupts* test =
23422 reinterpret_cast<RequestMultipleInterrupts*>(data);
23423 test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
23427 RequestMultipleInterrupts* test_;
23430 InterruptThread i_thread;
23435 TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
23438 static Local<Value> function_new_expected_env;
23439 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
23440 CHECK_EQ(function_new_expected_env, info.Data());
23441 info.GetReturnValue().Set(17);
23445 THREADED_TEST(FunctionNew) {
23447 v8::Isolate* isolate = env->GetIsolate();
23448 v8::HandleScope scope(isolate);
23449 Local<Object> data = v8::Object::New(isolate);
23450 function_new_expected_env = data;
23451 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
23452 env->Global()->Set(v8_str("func"), func);
23453 Local<Value> result = CompileRun("func();");
23454 CHECK_EQ(v8::Integer::New(isolate, 17), result);
23455 // Verify function not cached
23456 int serial_number =
23457 i::Smi::cast(v8::Utils::OpenHandle(*func)
23458 ->shared()->get_api_func_data()->serial_number())->value();
23459 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
23460 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
23461 i::Handle<i::Object> elm =
23462 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
23463 CHECK(elm->IsUndefined());
23464 // Verify that each Function::New creates a new function instance
23465 Local<Object> data2 = v8::Object::New(isolate);
23466 function_new_expected_env = data2;
23467 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
23468 CHECK(!func2->IsNull());
23469 CHECK_NE(func, func2);
23470 env->Global()->Set(v8_str("func2"), func2);
23471 Local<Value> result2 = CompileRun("func2();");
23472 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
23476 TEST(EscapeableHandleScope) {
23477 HandleScope outer_scope(CcTest::isolate());
23478 LocalContext context;
23479 const int runs = 10;
23480 Local<String> values[runs];
23481 for (int i = 0; i < runs; i++) {
23482 v8::EscapableHandleScope inner_scope(CcTest::isolate());
23483 Local<String> value;
23484 if (i != 0) value = v8_str("escape value");
23485 values[i] = inner_scope.Escape(value);
23487 for (int i = 0; i < runs; i++) {
23488 Local<String> expected;
23490 CHECK_EQ(v8_str("escape value"), values[i]);
23492 CHECK(values[i].IsEmpty());
23498 static void SetterWhichExpectsThisAndHolderToDiffer(
23499 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
23500 CHECK(info.Holder() != info.This());
23504 TEST(Regress239669) {
23505 LocalContext context;
23506 v8::Isolate* isolate = context->GetIsolate();
23507 v8::HandleScope scope(isolate);
23508 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23509 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
23510 context->Global()->Set(v8_str("P"), templ->NewInstance());
23515 "C1.prototype = P;"
23516 "for (var i = 0; i < 4; i++ ) {"
23522 class ApiCallOptimizationChecker {
23524 static Local<Object> data;
23525 static Local<Object> receiver;
23526 static Local<Object> holder;
23527 static Local<Object> callee;
23530 static void OptimizationCallback(
23531 const v8::FunctionCallbackInfo<v8::Value>& info) {
23532 CHECK(callee == info.Callee());
23533 CHECK(data == info.Data());
23534 CHECK(receiver == info.This());
23535 if (info.Length() == 1) {
23536 CHECK_EQ(v8_num(1), info[0]);
23538 CHECK(holder == info.Holder());
23540 info.GetReturnValue().Set(v8_str("returned"));
23544 enum SignatureType {
23546 kSignatureOnReceiver,
23547 kSignatureOnPrototype
23551 SignatureType signature_types[] =
23552 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
23553 for (unsigned i = 0; i < arraysize(signature_types); i++) {
23554 SignatureType signature_type = signature_types[i];
23555 for (int j = 0; j < 2; j++) {
23556 bool global = j == 0;
23557 int key = signature_type +
23558 arraysize(signature_types) * (global ? 1 : 0);
23559 Run(signature_type, global, key);
23564 void Run(SignatureType signature_type, bool global, int key) {
23565 v8::Isolate* isolate = CcTest::isolate();
23566 v8::HandleScope scope(isolate);
23567 // Build a template for signature checks.
23568 Local<v8::ObjectTemplate> signature_template;
23569 Local<v8::Signature> signature;
23571 Local<v8::FunctionTemplate> parent_template =
23572 FunctionTemplate::New(isolate);
23573 parent_template->SetHiddenPrototype(true);
23574 Local<v8::FunctionTemplate> function_template
23575 = FunctionTemplate::New(isolate);
23576 function_template->Inherit(parent_template);
23577 switch (signature_type) {
23580 case kSignatureOnReceiver:
23581 signature = v8::Signature::New(isolate, function_template);
23583 case kSignatureOnPrototype:
23584 signature = v8::Signature::New(isolate, parent_template);
23587 signature_template = function_template->InstanceTemplate();
23589 // Global object must pass checks.
23590 Local<v8::Context> context =
23591 v8::Context::New(isolate, NULL, signature_template);
23592 v8::Context::Scope context_scope(context);
23593 // Install regular object that can pass signature checks.
23594 Local<Object> function_receiver = signature_template->NewInstance();
23595 context->Global()->Set(v8_str("function_receiver"), function_receiver);
23596 // Get the holder objects.
23597 Local<Object> inner_global =
23598 Local<Object>::Cast(context->Global()->GetPrototype());
23599 // Install functions on hidden prototype object if there is one.
23600 data = Object::New(isolate);
23601 Local<FunctionTemplate> function_template = FunctionTemplate::New(
23602 isolate, OptimizationCallback, data, signature);
23603 Local<Function> function = function_template->GetFunction();
23604 Local<Object> global_holder = inner_global;
23605 Local<Object> function_holder = function_receiver;
23606 if (signature_type == kSignatureOnPrototype) {
23607 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
23608 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
23610 global_holder->Set(v8_str("g_f"), function);
23611 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
23612 function_holder->Set(v8_str("f"), function);
23613 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
23614 // Initialize expected values.
23618 receiver = context->Global();
23619 holder = inner_global;
23621 holder = function_receiver;
23622 // If not using a signature, add something else to the prototype chain
23623 // to test the case that holder != receiver
23624 if (signature_type == kNoSignature) {
23625 receiver = Local<Object>::Cast(CompileRun(
23626 "var receiver_subclass = {};\n"
23627 "receiver_subclass.__proto__ = function_receiver;\n"
23628 "receiver_subclass"));
23630 receiver = Local<Object>::Cast(CompileRun(
23631 "var receiver_subclass = function_receiver;\n"
23632 "receiver_subclass"));
23635 // With no signature, the holder is not set.
23636 if (signature_type == kNoSignature) holder = receiver;
23637 // build wrap_function
23638 i::ScopedVector<char> wrap_function(200);
23642 "function wrap_f_%d() { var f = g_f; return f(); }\n"
23643 "function wrap_get_%d() { return this.g_acc; }\n"
23644 "function wrap_set_%d() { return this.g_acc = 1; }\n",
23649 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
23650 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
23651 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
23654 // build source string
23655 i::ScopedVector<char> source(1000);
23658 "%s\n" // wrap functions
23659 "function wrap_f() { return wrap_f_%d(); }\n"
23660 "function wrap_get() { return wrap_get_%d(); }\n"
23661 "function wrap_set() { return wrap_set_%d(); }\n"
23662 "check = function(returned) {\n"
23663 " if (returned !== 'returned') { throw returned; }\n"
23666 "check(wrap_f());\n"
23667 "check(wrap_f());\n"
23668 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
23669 "check(wrap_f());\n"
23671 "check(wrap_get());\n"
23672 "check(wrap_get());\n"
23673 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
23674 "check(wrap_get());\n"
23676 "check = function(returned) {\n"
23677 " if (returned !== 1) { throw returned; }\n"
23679 "check(wrap_set());\n"
23680 "check(wrap_set());\n"
23681 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
23682 "check(wrap_set());\n",
23683 wrap_function.start(), key, key, key, key, key, key);
23684 v8::TryCatch try_catch;
23685 CompileRun(source.start());
23686 DCHECK(!try_catch.HasCaught());
23687 CHECK_EQ(9, count);
23692 Local<Object> ApiCallOptimizationChecker::data;
23693 Local<Object> ApiCallOptimizationChecker::receiver;
23694 Local<Object> ApiCallOptimizationChecker::holder;
23695 Local<Object> ApiCallOptimizationChecker::callee;
23696 int ApiCallOptimizationChecker::count = 0;
23699 TEST(TestFunctionCallOptimization) {
23700 i::FLAG_allow_natives_syntax = true;
23701 ApiCallOptimizationChecker checker;
23706 static const char* last_event_message;
23707 static int last_event_status;
23708 void StoringEventLoggerCallback(const char* message, int status) {
23709 last_event_message = message;
23710 last_event_status = status;
23714 TEST(EventLogging) {
23715 v8::Isolate* isolate = CcTest::isolate();
23716 isolate->SetEventLogger(StoringEventLoggerCallback);
23717 v8::internal::HistogramTimer histogramTimer(
23718 "V8.Test", 0, 10000, 50,
23719 reinterpret_cast<v8::internal::Isolate*>(isolate));
23720 histogramTimer.Start();
23721 CHECK_EQ("V8.Test", last_event_message);
23722 CHECK_EQ(0, last_event_status);
23723 histogramTimer.Stop();
23724 CHECK_EQ("V8.Test", last_event_message);
23725 CHECK_EQ(1, last_event_status);
23730 LocalContext context;
23731 v8::Isolate* isolate = context->GetIsolate();
23732 v8::HandleScope scope(isolate);
23733 Handle<Object> global = context->Global();
23736 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
23737 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
23738 Handle<v8::Promise> p = pr->GetPromise();
23739 Handle<v8::Promise> r = rr->GetPromise();
23740 CHECK_EQ(isolate, p->GetIsolate());
23742 // IsPromise predicate.
23743 CHECK(p->IsPromise());
23744 CHECK(r->IsPromise());
23745 Handle<Value> o = v8::Object::New(isolate);
23746 CHECK(!o->IsPromise());
23748 // Resolution and rejection.
23749 pr->Resolve(v8::Integer::New(isolate, 1));
23750 CHECK(p->IsPromise());
23751 rr->Reject(v8::Integer::New(isolate, 2));
23752 CHECK(r->IsPromise());
23754 // Chaining non-pending promises.
23758 "function f1(x) { x1 = x; return x+1 };\n"
23759 "function f2(x) { x2 = x; return x+1 };\n");
23760 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
23761 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
23764 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23765 isolate->RunMicrotasks();
23766 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23769 isolate->RunMicrotasks();
23770 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23773 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23774 isolate->RunMicrotasks();
23775 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
23778 isolate->RunMicrotasks();
23779 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23781 // Chaining pending promises.
23782 CompileRun("x1 = x2 = 0;");
23783 pr = v8::Promise::Resolver::New(isolate);
23784 rr = v8::Promise::Resolver::New(isolate);
23786 pr->GetPromise()->Chain(f1);
23787 rr->GetPromise()->Catch(f2);
23788 isolate->RunMicrotasks();
23789 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23790 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23792 pr->Resolve(v8::Integer::New(isolate, 1));
23793 rr->Reject(v8::Integer::New(isolate, 2));
23794 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23795 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23797 isolate->RunMicrotasks();
23798 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23799 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
23802 CompileRun("x1 = x2 = 0;");
23803 pr = v8::Promise::Resolver::New(isolate);
23804 pr->GetPromise()->Chain(f1)->Chain(f2);
23805 pr->Resolve(v8::Integer::New(isolate, 3));
23806 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23807 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23808 isolate->RunMicrotasks();
23809 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23810 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23812 CompileRun("x1 = x2 = 0;");
23813 rr = v8::Promise::Resolver::New(isolate);
23814 rr->GetPromise()->Catch(f1)->Chain(f2);
23815 rr->Reject(v8::Integer::New(isolate, 3));
23816 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23817 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23818 isolate->RunMicrotasks();
23819 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23820 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23824 TEST(PromiseThen) {
23825 LocalContext context;
23826 v8::Isolate* isolate = context->GetIsolate();
23827 v8::HandleScope scope(isolate);
23828 Handle<Object> global = context->Global();
23831 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
23832 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
23833 Handle<v8::Promise> p = pr->GetPromise();
23834 Handle<v8::Promise> q = qr->GetPromise();
23836 CHECK(p->IsPromise());
23837 CHECK(q->IsPromise());
23839 pr->Resolve(v8::Integer::New(isolate, 1));
23842 // Chaining non-pending promises.
23846 "function f1(x) { x1 = x; return x+1 };\n"
23847 "function f2(x) { x2 = x; return x+1 };\n");
23848 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
23849 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
23853 CHECK(global->Get(v8_str("x1"))->IsNumber());
23854 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23855 isolate->RunMicrotasks();
23856 CHECK(!global->Get(v8_str("x1"))->IsNumber());
23857 CHECK_EQ(p, global->Get(v8_str("x1")));
23860 CompileRun("x1 = x2 = 0;");
23862 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23863 isolate->RunMicrotasks();
23864 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23867 CompileRun("x1 = x2 = 0;");
23868 pr = v8::Promise::Resolver::New(isolate);
23869 qr = v8::Promise::Resolver::New(isolate);
23872 qr->GetPromise()->Then(f1)->Then(f2);
23874 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23875 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23876 isolate->RunMicrotasks();
23877 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23878 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23880 pr->Resolve(v8::Integer::New(isolate, 3));
23882 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23883 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23884 isolate->RunMicrotasks();
23885 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23886 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23890 TEST(DisallowJavascriptExecutionScope) {
23891 LocalContext context;
23892 v8::Isolate* isolate = context->GetIsolate();
23893 v8::HandleScope scope(isolate);
23894 v8::Isolate::DisallowJavascriptExecutionScope no_js(
23895 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23900 TEST(AllowJavascriptExecutionScope) {
23901 LocalContext context;
23902 v8::Isolate* isolate = context->GetIsolate();
23903 v8::HandleScope scope(isolate);
23904 v8::Isolate::DisallowJavascriptExecutionScope no_js(
23905 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23906 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23907 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23908 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
23914 TEST(ThrowOnJavascriptExecution) {
23915 LocalContext context;
23916 v8::Isolate* isolate = context->GetIsolate();
23917 v8::HandleScope scope(isolate);
23918 v8::TryCatch try_catch;
23919 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23920 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23922 CHECK(try_catch.HasCaught());
23926 TEST(Regress354123) {
23927 LocalContext current;
23928 v8::Isolate* isolate = current->GetIsolate();
23929 v8::HandleScope scope(isolate);
23931 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
23932 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
23933 current->Global()->Set(v8_str("friend"), templ->NewInstance());
23935 // Test access using __proto__ from the prototype chain.
23936 named_access_count = 0;
23937 CompileRun("friend.__proto__ = {};");
23938 CHECK_EQ(2, named_access_count);
23939 CompileRun("friend.__proto__;");
23940 CHECK_EQ(4, named_access_count);
23942 // Test access using __proto__ as a hijacked function (A).
23943 named_access_count = 0;
23944 CompileRun("var p = Object.prototype;"
23945 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
23946 "f.call(friend, {});");
23947 CHECK_EQ(1, named_access_count);
23948 CompileRun("var p = Object.prototype;"
23949 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
23950 "f.call(friend);");
23951 CHECK_EQ(2, named_access_count);
23953 // Test access using __proto__ as a hijacked function (B).
23954 named_access_count = 0;
23955 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
23956 "f.call(friend, {});");
23957 CHECK_EQ(1, named_access_count);
23958 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
23959 "f.call(friend);");
23960 CHECK_EQ(2, named_access_count);
23962 // Test access using Object.setPrototypeOf reflective method.
23963 named_access_count = 0;
23964 CompileRun("Object.setPrototypeOf(friend, {});");
23965 CHECK_EQ(1, named_access_count);
23966 CompileRun("Object.getPrototypeOf(friend);");
23967 CHECK_EQ(2, named_access_count);
23971 TEST(CaptureStackTraceForStackOverflow) {
23972 v8::internal::FLAG_stack_size = 150;
23973 LocalContext current;
23974 v8::Isolate* isolate = current->GetIsolate();
23975 v8::HandleScope scope(isolate);
23976 V8::SetCaptureStackTraceForUncaughtExceptions(
23977 true, 10, v8::StackTrace::kDetailed);
23978 v8::TryCatch try_catch;
23979 CompileRun("(function f(x) { f(x+1); })(0)");
23980 CHECK(try_catch.HasCaught());
23984 TEST(ScriptNameAndLineNumber) {
23986 v8::Isolate* isolate = env->GetIsolate();
23987 v8::HandleScope scope(isolate);
23988 const char* url = "http://www.foo.com/foo.js";
23989 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
23990 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
23991 Local<Script> script = v8::ScriptCompiler::Compile(
23992 isolate, &script_source);
23993 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
23994 CHECK(!script_name.IsEmpty());
23995 CHECK(script_name->IsString());
23996 String::Utf8Value utf8_name(script_name);
23997 CHECK_EQ(url, *utf8_name);
23998 int line_number = script->GetUnboundScript()->GetLineNumber(0);
23999 CHECK_EQ(13, line_number);
24003 void SourceURLHelper(const char* source, const char* expected_source_url,
24004 const char* expected_source_mapping_url) {
24005 Local<Script> script = v8_compile(source);
24006 if (expected_source_url != NULL) {
24007 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
24008 CHECK_EQ(expected_source_url, *url);
24010 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
24012 if (expected_source_mapping_url != NULL) {
24013 v8::String::Utf8Value url(
24014 script->GetUnboundScript()->GetSourceMappingURL());
24015 CHECK_EQ(expected_source_mapping_url, *url);
24017 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
24022 TEST(ScriptSourceURLAndSourceMappingURL) {
24024 v8::Isolate* isolate = env->GetIsolate();
24025 v8::HandleScope scope(isolate);
24026 SourceURLHelper("function foo() {}\n"
24027 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
24028 SourceURLHelper("function foo() {}\n"
24029 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
24031 // Both sourceURL and sourceMappingURL.
24032 SourceURLHelper("function foo() {}\n"
24033 "//# sourceURL=bar3.js\n"
24034 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
24036 // Two source URLs; the first one is ignored.
24037 SourceURLHelper("function foo() {}\n"
24038 "//# sourceURL=ignoreme.js\n"
24039 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
24040 SourceURLHelper("function foo() {}\n"
24041 "//# sourceMappingURL=ignoreme.js\n"
24042 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
24044 // SourceURL or sourceMappingURL in the middle of the script.
24045 SourceURLHelper("function foo() {}\n"
24046 "//# sourceURL=bar7.js\n"
24047 "function baz() {}\n", "bar7.js", NULL);
24048 SourceURLHelper("function foo() {}\n"
24049 "//# sourceMappingURL=bar8.js\n"
24050 "function baz() {}\n", NULL, "bar8.js");
24052 // Too much whitespace.
24053 SourceURLHelper("function foo() {}\n"
24054 "//# sourceURL=bar9.js\n"
24055 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
24056 SourceURLHelper("function foo() {}\n"
24057 "//# sourceURL =bar11.js\n"
24058 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
24060 // Disallowed characters in value.
24061 SourceURLHelper("function foo() {}\n"
24062 "//# sourceURL=bar13 .js \n"
24063 "//# sourceMappingURL=bar14 .js \n",
24065 SourceURLHelper("function foo() {}\n"
24066 "//# sourceURL=bar15\t.js \n"
24067 "//# sourceMappingURL=bar16\t.js \n",
24069 SourceURLHelper("function foo() {}\n"
24070 "//# sourceURL=bar17'.js \n"
24071 "//# sourceMappingURL=bar18'.js \n",
24073 SourceURLHelper("function foo() {}\n"
24074 "//# sourceURL=bar19\".js \n"
24075 "//# sourceMappingURL=bar20\".js \n",
24078 // Not too much whitespace.
24079 SourceURLHelper("function foo() {}\n"
24080 "//# sourceURL= bar21.js \n"
24081 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
24085 TEST(GetOwnPropertyDescriptor) {
24087 v8::Isolate* isolate = env->GetIsolate();
24088 v8::HandleScope scope(isolate);
24090 "var x = { value : 13};"
24091 "Object.defineProperty(x, 'p0', {value : 12});"
24092 "Object.defineProperty(x, 'p1', {"
24093 " set : function(value) { this.value = value; },"
24094 " get : function() { return this.value; },"
24096 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
24097 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
24098 CHECK(desc->IsUndefined());
24099 desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
24100 CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
24101 desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
24102 Local<Function> set =
24103 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
24104 Local<Function> get =
24105 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
24106 CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
24107 Handle<Value> args[] = { v8_num(14) };
24108 set->Call(x, 1, args);
24109 CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));
24113 TEST(Regress411877) {
24114 v8::Isolate* isolate = CcTest::isolate();
24115 v8::HandleScope handle_scope(isolate);
24116 v8::Handle<v8::ObjectTemplate> object_template =
24117 v8::ObjectTemplate::New(isolate);
24118 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
24119 IndexedAccessCounter);
24121 v8::Handle<Context> context = Context::New(isolate);
24122 v8::Context::Scope context_scope(context);
24124 context->Global()->Set(v8_str("o"), object_template->NewInstance());
24125 CompileRun("Object.getOwnPropertyNames(o)");
24129 TEST(GetHiddenPropertyTableAfterAccessCheck) {
24130 v8::Isolate* isolate = CcTest::isolate();
24131 v8::HandleScope handle_scope(isolate);
24132 v8::Handle<v8::ObjectTemplate> object_template =
24133 v8::ObjectTemplate::New(isolate);
24134 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
24135 IndexedAccessCounter);
24137 v8::Handle<Context> context = Context::New(isolate);
24138 v8::Context::Scope context_scope(context);
24140 v8::Handle<v8::Object> obj = object_template->NewInstance();
24141 obj->Set(v8_str("key"), v8_str("value"));
24142 obj->Delete(v8_str("key"));
24144 obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
24148 TEST(Regress411793) {
24149 v8::Isolate* isolate = CcTest::isolate();
24150 v8::HandleScope handle_scope(isolate);
24151 v8::Handle<v8::ObjectTemplate> object_template =
24152 v8::ObjectTemplate::New(isolate);
24153 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
24154 IndexedAccessCounter);
24156 v8::Handle<Context> context = Context::New(isolate);
24157 v8::Context::Scope context_scope(context);
24159 context->Global()->Set(v8_str("o"), object_template->NewInstance());
24161 "Object.defineProperty(o, 'key', "
24162 " { get: function() {}, set: function() {} });");
24165 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
24167 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
24169 virtual size_t GetMoreData(const uint8_t** src) {
24170 // Unlike in real use cases, this function will never block.
24171 if (chunks_[index_] == NULL) {
24174 // Copy the data, since the caller takes ownership of it.
24175 size_t len = strlen(chunks_[index_]);
24176 // We don't need to zero-terminate since we return the length.
24177 uint8_t* copy = new uint8_t[len];
24178 memcpy(copy, chunks_[index_], len);
24184 // Helper for constructing a string from chunks (the compilation needs it
24186 static char* FullSourceString(const char** chunks) {
24187 size_t total_len = 0;
24188 for (size_t i = 0; chunks[i] != NULL; ++i) {
24189 total_len += strlen(chunks[i]);
24191 char* full_string = new char[total_len + 1];
24193 for (size_t i = 0; chunks[i] != NULL; ++i) {
24194 size_t len = strlen(chunks[i]);
24195 memcpy(full_string + offset, chunks[i], len);
24198 full_string[total_len] = 0;
24199 return full_string;
24203 const char** chunks_;
24208 // Helper function for running streaming tests.
24209 void RunStreamingTest(const char** chunks,
24210 v8::ScriptCompiler::StreamedSource::Encoding encoding =
24211 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24212 bool expected_success = true) {
24214 v8::Isolate* isolate = env->GetIsolate();
24215 v8::HandleScope scope(isolate);
24216 v8::TryCatch try_catch;
24218 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
24220 v8::ScriptCompiler::ScriptStreamingTask* task =
24221 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
24223 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24224 // task here in the main thread.
24228 v8::ScriptOrigin origin(v8_str("http://foo.com"));
24229 char* full_source = TestSourceStream::FullSourceString(chunks);
24231 // The possible errors are only produced while compiling.
24232 CHECK_EQ(false, try_catch.HasCaught());
24234 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
24235 isolate, &source, v8_str(full_source), origin);
24236 if (expected_success) {
24237 CHECK(!script.IsEmpty());
24238 v8::Handle<Value> result(script->Run());
24239 // All scripts are supposed to return the fixed value 13 when ran.
24240 CHECK_EQ(13, result->Int32Value());
24242 CHECK(script.IsEmpty());
24243 CHECK(try_catch.HasCaught());
24245 delete[] full_source;
24249 TEST(StreamingSimpleScript) {
24250 // This script is unrealistically small, since no one chunk is enough to fill
24251 // the backing buffer of Scanner, let alone overflow it.
24252 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24254 RunStreamingTest(chunks);
24258 TEST(StreamingBiggerScript) {
24259 const char* chunk1 =
24260 "function foo() {\n"
24261 " // Make this chunk sufficiently long so that it will overflow the\n"
24262 " // backing buffer of the Scanner.\n"
24264 " var result = 0;\n"
24265 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24267 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24269 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24271 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
24272 " return result;\n"
24274 const char* chunks[] = {chunk1, "foo(); ", NULL};
24275 RunStreamingTest(chunks);
24279 TEST(StreamingScriptWithParseError) {
24280 // Test that parse errors from streamed scripts are propagated correctly.
24283 " // This will result in a parse error.\n"
24284 " var if else then foo";
24285 char chunk2[] = " 13\n";
24286 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24288 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
24291 // Test that the next script succeeds normally.
24294 " // This will be parsed successfully.\n"
24295 " function foo() { return ";
24296 char chunk2[] = " 13; }\n";
24297 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24299 RunStreamingTest(chunks);
24304 TEST(StreamingUtf8Script) {
24305 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
24307 const char* chunk1 =
24308 "function foo() {\n"
24309 " // This function will contain an UTF-8 character which is not in\n"
24311 " var foob\xec\x92\x81r = 13;\n"
24312 " return foob\xec\x92\x81r;\n"
24314 const char* chunks[] = {chunk1, "foo(); ", NULL};
24315 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24319 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
24320 // A sanity check to prove that the approach of splitting UTF-8
24321 // characters is correct. Here is an UTF-8 character which will take three
24323 const char* reference = "\xec\x92\x81";
24324 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
24327 "function foo() {\n"
24328 " // This function will contain an UTF-8 character which is not in\n"
24333 " return foob\xec\x92\x81r;\n"
24335 for (int i = 0; i < 3; ++i) {
24336 chunk2[i] = reference[i];
24338 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24339 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24343 TEST(StreamingUtf8ScriptWithSplitCharacters) {
24344 // Stream data where a multi-byte UTF-8 character is split between two data
24346 const char* reference = "\xec\x92\x81";
24348 "function foo() {\n"
24349 " // This function will contain an UTF-8 character which is not in\n"
24354 " return foob\xec\x92\x81r;\n"
24356 chunk1[strlen(chunk1) - 1] = reference[0];
24357 chunk2[0] = reference[1];
24358 chunk2[1] = reference[2];
24359 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24360 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24364 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
24365 // Tests edge cases which should still be decoded correctly.
24367 // Case 1: a chunk contains only bytes for a split character (and no other
24368 // data). This kind of a chunk would be exceptionally small, but we should
24369 // still decode it correctly.
24370 const char* reference = "\xec\x92\x81";
24371 // The small chunk is at the beginning of the split character
24374 "function foo() {\n"
24375 " // This function will contain an UTF-8 character which is not in\n"
24378 char chunk2[] = "XX";
24381 " return foob\xec\x92\x81r;\n"
24383 chunk2[0] = reference[0];
24384 chunk2[1] = reference[1];
24385 chunk3[0] = reference[2];
24386 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24387 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24389 // The small chunk is at the end of a character
24392 "function foo() {\n"
24393 " // This function will contain an UTF-8 character which is not in\n"
24396 char chunk2[] = "XX";
24399 " return foob\xec\x92\x81r;\n"
24401 chunk1[strlen(chunk1) - 1] = reference[0];
24402 chunk2[0] = reference[1];
24403 chunk2[1] = reference[2];
24404 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24405 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24407 // Case 2: the script ends with a multi-byte character. Make sure that it's
24408 // decoded correctly and not just ignored.
24411 "var foob\xec\x92\x81 = 13;\n"
24412 "foob\xec\x92\x81";
24413 const char* chunks[] = {chunk1, NULL};
24414 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24419 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
24420 // Test cases where a UTF-8 character is split over several chunks. Those
24421 // cases are not supported (the embedder should give the data in big enough
24422 // chunks), but we shouldn't crash, just produce a parse error.
24423 const char* reference = "\xec\x92\x81";
24425 "function foo() {\n"
24426 " // This function will contain an UTF-8 character which is not in\n"
24429 char chunk2[] = "X";
24432 " return foob\xec\x92\x81r;\n"
24434 chunk1[strlen(chunk1) - 1] = reference[0];
24435 chunk2[0] = reference[1];
24436 chunk3[0] = reference[2];
24437 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24439 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24443 TEST(StreamingProducesParserCache) {
24444 i::FLAG_min_preparse_length = 0;
24445 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24449 v8::Isolate* isolate = env->GetIsolate();
24450 v8::HandleScope scope(isolate);
24452 v8::ScriptCompiler::StreamedSource source(
24453 new TestSourceStream(chunks),
24454 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
24455 v8::ScriptCompiler::ScriptStreamingTask* task =
24456 v8::ScriptCompiler::StartStreamingScript(
24457 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
24459 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24460 // task here in the main thread.
24464 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
24465 CHECK(cached_data != NULL);
24466 CHECK(cached_data->data != NULL);
24467 CHECK(!cached_data->rejected);
24468 CHECK_GT(cached_data->length, 0);
24472 TEST(StreamingScriptWithInvalidUtf8) {
24473 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
24474 // chunk don't produce a crash.
24475 const char* reference = "\xec\x92\x81\x80\x80";
24477 "function foo() {\n"
24478 " // This function will contain an UTF-8 character which is not in\n"
24480 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
24483 " return foob\xec\x92\x81\x80\x80r;\n"
24485 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
24487 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24488 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24492 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
24493 // Regression test: Stream data where there are several multi-byte UTF-8
24494 // characters in a sequence and one of them is split between two data chunks.
24495 const char* reference = "\xec\x92\x81";
24497 "function foo() {\n"
24498 " // This function will contain an UTF-8 character which is not in\n"
24500 " var foob\xec\x92\x81X";
24503 " return foob\xec\x92\x81\xec\x92\x81r;\n"
24505 chunk1[strlen(chunk1) - 1] = reference[0];
24506 chunk2[0] = reference[1];
24507 chunk2[1] = reference[2];
24508 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24509 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24513 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
24514 // Another regression test, similar to the previous one. The difference is
24515 // that the split character is not the last one in the sequence.
24516 const char* reference = "\xec\x92\x81";
24518 "function foo() {\n"
24519 " // This function will contain an UTF-8 character which is not in\n"
24523 "XX\xec\x92\x81r = 13;\n"
24524 " return foob\xec\x92\x81\xec\x92\x81r;\n"
24526 chunk1[strlen(chunk1) - 1] = reference[0];
24527 chunk2[0] = reference[1];
24528 chunk2[1] = reference[2];
24529 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24530 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24534 void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
24535 const char* garbage = "garbage garbage garbage garbage.";
24536 const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
24538 v8::ScriptCompiler::CachedData* cached_data =
24539 new v8::ScriptCompiler::CachedData(data, length);
24540 DCHECK(!cached_data->rejected);
24541 v8::ScriptOrigin origin(v8_str("origin"));
24542 v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
24543 v8::Handle<v8::Script> script =
24544 v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
24545 CHECK(cached_data->rejected);
24546 CHECK_EQ(42, script->Run()->Int32Value());
24550 TEST(InvalidCacheData) {
24551 v8::V8::Initialize();
24552 v8::HandleScope scope(CcTest::isolate());
24553 LocalContext context;
24554 TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
24555 TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
24559 TEST(ParserCacheRejectedGracefully) {
24560 i::FLAG_min_preparse_length = 0;
24561 v8::V8::Initialize();
24562 v8::HandleScope scope(CcTest::isolate());
24563 LocalContext context;
24564 // Produce valid cached data.
24565 v8::ScriptOrigin origin(v8_str("origin"));
24566 v8::Local<v8::String> source_str = v8_str("function foo() {}");
24567 v8::ScriptCompiler::Source source(source_str, origin);
24568 v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
24569 CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
24570 CHECK(!script.IsEmpty());
24571 const v8::ScriptCompiler::CachedData* original_cached_data =
24572 source.GetCachedData();
24573 CHECK(original_cached_data != NULL);
24574 CHECK(original_cached_data->data != NULL);
24575 CHECK(!original_cached_data->rejected);
24576 CHECK_GT(original_cached_data->length, 0);
24577 // Recompiling the same script with it won't reject the data.
24579 v8::ScriptCompiler::Source source_with_cached_data(
24580 source_str, origin,
24581 new v8::ScriptCompiler::CachedData(original_cached_data->data,
24582 original_cached_data->length));
24583 v8::Handle<v8::Script> script =
24584 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
24585 v8::ScriptCompiler::kConsumeParserCache);
24586 CHECK(!script.IsEmpty());
24587 const v8::ScriptCompiler::CachedData* new_cached_data =
24588 source_with_cached_data.GetCachedData();
24589 CHECK(new_cached_data != NULL);
24590 CHECK(!new_cached_data->rejected);
24592 // Compile an incompatible script with the cached data. The new script doesn't
24593 // have the same starting position for the function as the old one, so the old
24594 // cached data will be incompatible with it and will be rejected.
24596 v8::Local<v8::String> incompatible_source_str =
24597 v8_str(" function foo() {}");
24598 v8::ScriptCompiler::Source source_with_cached_data(
24599 incompatible_source_str, origin,
24600 new v8::ScriptCompiler::CachedData(original_cached_data->data,
24601 original_cached_data->length));
24602 v8::Handle<v8::Script> script =
24603 v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
24604 v8::ScriptCompiler::kConsumeParserCache);
24605 CHECK(!script.IsEmpty());
24606 const v8::ScriptCompiler::CachedData* new_cached_data =
24607 source_with_cached_data.GetCachedData();
24608 CHECK(new_cached_data != NULL);
24609 CHECK(new_cached_data->rejected);
24614 TEST(StringConcatOverflow) {
24615 v8::V8::Initialize();
24616 v8::HandleScope scope(CcTest::isolate());
24617 RandomLengthOneByteResource* r =
24618 new RandomLengthOneByteResource(i::String::kMaxLength);
24619 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
24620 CHECK(!str.IsEmpty());
24621 v8::TryCatch try_catch;
24622 v8::Local<v8::String> result = v8::String::Concat(str, str);
24623 CHECK(result.IsEmpty());
24624 CHECK(!try_catch.HasCaught());
24628 TEST(TurboAsmDisablesNeuter) {
24629 v8::V8::Initialize();
24630 v8::HandleScope scope(CcTest::isolate());
24631 LocalContext context;
24632 #if V8_TURBOFAN_TARGET
24633 bool should_be_neuterable = !i::FLAG_turbo_asm;
24635 bool should_be_neuterable = true;
24638 "function Module(stdlib, foreign, heap) {"
24640 " var MEM32 = new stdlib.Int32Array(heap);"
24641 " function load() { return MEM32[0]; }"
24642 " return { load: load };"
24644 "var buffer = new ArrayBuffer(4);"
24645 "Module(this, {}, buffer).load();"
24648 v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
24649 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
24651 const char* store =
24652 "function Module(stdlib, foreign, heap) {"
24654 " var MEM32 = new stdlib.Int32Array(heap);"
24655 " function store() { MEM32[0] = 0; }"
24656 " return { store: store };"
24658 "var buffer = new ArrayBuffer(4);"
24659 "Module(this, {}, buffer).store();"
24662 result = CompileRun(store).As<v8::ArrayBuffer>();
24663 CHECK_EQ(should_be_neuterable, result->IsNeuterable());
24667 TEST(GetPrototypeAccessControl) {
24668 i::FLAG_allow_natives_syntax = true;
24669 v8::Isolate* isolate = CcTest::isolate();
24670 v8::HandleScope handle_scope(isolate);
24673 v8::Handle<v8::ObjectTemplate> obj_template =
24674 v8::ObjectTemplate::New(isolate);
24675 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
24676 BlockEverythingIndexed);
24678 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
24681 v8::TryCatch try_catch;
24683 "function f() { %_GetPrototype(prohibited); }"
24684 "%OptimizeFunctionOnNextCall(f);"
24686 CHECK(try_catch.HasCaught());
24691 TEST(GetPrototypeHidden) {
24692 i::FLAG_allow_natives_syntax = true;
24693 v8::Isolate* isolate = CcTest::isolate();
24694 v8::HandleScope handle_scope(isolate);
24697 Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
24698 t->SetHiddenPrototype(true);
24699 Handle<Object> proto = t->GetFunction()->NewInstance();
24700 Handle<Object> object = Object::New(isolate);
24701 Handle<Object> proto2 = Object::New(isolate);
24702 object->SetPrototype(proto);
24703 proto->SetPrototype(proto2);
24705 env->Global()->Set(v8_str("object"), object);
24706 env->Global()->Set(v8_str("proto"), proto);
24707 env->Global()->Set(v8_str("proto2"), proto2);
24709 v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
24710 CHECK(result->Equals(proto2));
24712 result = CompileRun(
24713 "function f() { return %_GetPrototype(object); }"
24714 "%OptimizeFunctionOnNextCall(f);"
24716 CHECK(result->Equals(proto2));
24720 TEST(ClassPrototypeCreationContext) {
24721 i::FLAG_harmony_classes = true;
24722 v8::Isolate* isolate = CcTest::isolate();
24723 v8::HandleScope handle_scope(isolate);
24726 Handle<Object> result = Handle<Object>::Cast(
24727 CompileRun("'use strict'; class Example { }; Example.prototype"));
24728 CHECK(env.local() == result->CreationContext());