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 i::ScopedVector<char> source(200);
191 "for (var i = 0; i < 10; i++) {"
195 signature_callback_count = 0;
196 signature_expected_receiver = receiver;
197 bool expected_to_throw = receiver.IsEmpty();
198 v8::TryCatch try_catch;
199 CompileRun(source.start());
200 CHECK_EQ(expected_to_throw, try_catch.HasCaught());
201 if (!expected_to_throw) {
202 CHECK_EQ(10, signature_callback_count);
204 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
205 try_catch.Exception()->ToString());
210 THREADED_TEST(ReceiverSignature) {
212 v8::Isolate* isolate = env->GetIsolate();
213 v8::HandleScope scope(isolate);
215 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
216 v8::Handle<v8::Signature> sig = v8::Signature::New(isolate, fun);
217 v8::Handle<v8::FunctionTemplate> callback_sig =
218 v8::FunctionTemplate::New(
219 isolate, IncrementingSignatureCallback, Local<Value>(), sig);
220 v8::Handle<v8::FunctionTemplate> callback =
221 v8::FunctionTemplate::New(isolate, IncrementingSignatureCallback);
222 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(isolate);
223 sub_fun->Inherit(fun);
224 v8::Handle<v8::FunctionTemplate> unrel_fun =
225 v8::FunctionTemplate::New(isolate);
226 // Install properties.
227 v8::Handle<v8::ObjectTemplate> fun_proto = fun->PrototypeTemplate();
228 fun_proto->Set(v8_str("prop_sig"), callback_sig);
229 fun_proto->Set(v8_str("prop"), callback);
230 fun_proto->SetAccessorProperty(
231 v8_str("accessor_sig"), callback_sig, callback_sig);
232 fun_proto->SetAccessorProperty(v8_str("accessor"), callback, callback);
233 // Instantiate templates.
234 Local<Value> fun_instance = fun->InstanceTemplate()->NewInstance();
235 Local<Value> sub_fun_instance = sub_fun->InstanceTemplate()->NewInstance();
236 // Setup global variables.
237 env->Global()->Set(v8_str("Fun"), fun->GetFunction());
238 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction());
239 env->Global()->Set(v8_str("fun_instance"), fun_instance);
240 env->Global()->Set(v8_str("sub_fun_instance"), sub_fun_instance);
242 "var accessor_sig_key = 'accessor_sig';"
243 "var accessor_key = 'accessor';"
244 "var prop_sig_key = 'prop_sig';"
245 "var prop_key = 'prop';"
247 "function copy_props(obj) {"
248 " var keys = [accessor_sig_key, accessor_key, prop_sig_key, prop_key];"
249 " var source = Fun.prototype;"
250 " for (var i in keys) {"
251 " var key = keys[i];"
252 " var desc = Object.getOwnPropertyDescriptor(source, key);"
253 " Object.defineProperty(obj, key, desc);"
259 "var unrel = new UnrelFun();"
260 "copy_props(unrel);");
261 // Test with and without ICs
262 const char* test_objects[] = {
263 "fun_instance", "sub_fun_instance", "obj", "unrel" };
264 unsigned bad_signature_start_offset = 2;
265 for (unsigned i = 0; i < arraysize(test_objects); i++) {
266 i::ScopedVector<char> source(200);
268 source, "var test_object = %s; test_object", test_objects[i]);
269 Local<Value> test_object = CompileRun(source.start());
270 TestSignature("test_object.prop();", test_object);
271 TestSignature("test_object.accessor;", test_object);
272 TestSignature("test_object[accessor_key];", test_object);
273 TestSignature("test_object.accessor = 1;", test_object);
274 TestSignature("test_object[accessor_key] = 1;", test_object);
275 if (i >= bad_signature_start_offset) test_object = Local<Value>();
276 TestSignature("test_object.prop_sig();", test_object);
277 TestSignature("test_object.accessor_sig;", test_object);
278 TestSignature("test_object[accessor_sig_key];", test_object);
279 TestSignature("test_object.accessor_sig = 1;", test_object);
280 TestSignature("test_object[accessor_sig_key] = 1;", test_object);
285 THREADED_TEST(ArgumentSignature) {
287 v8::Isolate* isolate = env->GetIsolate();
288 v8::HandleScope scope(isolate);
289 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(isolate);
290 cons->SetClassName(v8_str("Cons"));
291 v8::Handle<v8::Signature> sig = v8::Signature::New(
292 isolate, v8::Handle<v8::FunctionTemplate>(), 1, &cons);
293 v8::Handle<v8::FunctionTemplate> fun =
294 v8::FunctionTemplate::New(isolate,
298 env->Global()->Set(v8_str("Cons"), cons->GetFunction());
299 env->Global()->Set(v8_str("Fun1"), fun->GetFunction());
301 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';");
302 CHECK(value1->IsTrue());
304 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';");
305 CHECK(value2->IsTrue());
307 v8::Handle<Value> value3 = CompileRun("Fun1() == '';");
308 CHECK(value3->IsTrue());
310 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(isolate);
311 cons1->SetClassName(v8_str("Cons1"));
312 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(isolate);
313 cons2->SetClassName(v8_str("Cons2"));
314 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(isolate);
315 cons3->SetClassName(v8_str("Cons3"));
317 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 };
318 v8::Handle<v8::Signature> wsig = v8::Signature::New(
319 isolate, v8::Handle<v8::FunctionTemplate>(), 3, args);
320 v8::Handle<v8::FunctionTemplate> fun2 =
321 v8::FunctionTemplate::New(isolate,
326 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction());
327 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction());
328 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction());
329 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction());
330 v8::Handle<Value> value4 = CompileRun(
331 "Fun2(new Cons1(), new Cons2(), new Cons3()) =="
332 "'[object Cons1],[object Cons2],[object Cons3]'");
333 CHECK(value4->IsTrue());
335 v8::Handle<Value> value5 = CompileRun(
336 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'");
337 CHECK(value5->IsTrue());
339 v8::Handle<Value> value6 = CompileRun(
340 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'");
341 CHECK(value6->IsTrue());
343 v8::Handle<Value> value7 = CompileRun(
344 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == "
345 "'[object Cons1],[object Cons2],[object Cons3],d';");
346 CHECK(value7->IsTrue());
348 v8::Handle<Value> value8 = CompileRun(
349 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'");
350 CHECK(value8->IsTrue());
354 THREADED_TEST(HulIgennem) {
356 v8::Isolate* isolate = env->GetIsolate();
357 v8::HandleScope scope(isolate);
358 v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
359 Local<String> undef_str = undef->ToString();
360 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
361 undef_str->WriteUtf8(value);
362 CHECK_EQ(0, strcmp(value, "undefined"));
363 i::DeleteArray(value);
367 THREADED_TEST(Access) {
369 v8::Isolate* isolate = env->GetIsolate();
370 v8::HandleScope scope(isolate);
371 Local<v8::Object> obj = v8::Object::New(isolate);
372 Local<Value> foo_before = obj->Get(v8_str("foo"));
373 CHECK(foo_before->IsUndefined());
374 Local<String> bar_str = v8_str("bar");
375 obj->Set(v8_str("foo"), bar_str);
376 Local<Value> foo_after = obj->Get(v8_str("foo"));
377 CHECK(!foo_after->IsUndefined());
378 CHECK(foo_after->IsString());
379 CHECK_EQ(bar_str, foo_after);
383 THREADED_TEST(AccessElement) {
385 v8::HandleScope scope(env->GetIsolate());
386 Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
387 Local<Value> before = obj->Get(1);
388 CHECK(before->IsUndefined());
389 Local<String> bar_str = v8_str("bar");
390 obj->Set(1, bar_str);
391 Local<Value> after = obj->Get(1);
392 CHECK(!after->IsUndefined());
393 CHECK(after->IsString());
394 CHECK_EQ(bar_str, after);
396 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>();
397 CHECK_EQ(v8_str("a"), value->Get(0));
398 CHECK_EQ(v8_str("b"), value->Get(1));
402 THREADED_TEST(Script) {
404 v8::HandleScope scope(env->GetIsolate());
405 const char* source = "1 + 2 + 3";
406 Local<Script> script = v8_compile(source);
407 CHECK_EQ(6, script->Run()->Int32Value());
411 class TestResource: public String::ExternalStringResource {
413 explicit TestResource(uint16_t* data, int* counter = NULL,
414 bool owning_data = true)
415 : data_(data), length_(0), counter_(counter), owning_data_(owning_data) {
416 while (data[length_]) ++length_;
420 if (owning_data_) i::DeleteArray(data_);
421 if (counter_ != NULL) ++*counter_;
424 const uint16_t* data() const {
428 size_t length() const {
440 class TestOneByteResource : public String::ExternalOneByteStringResource {
442 explicit TestOneByteResource(const char* data, int* counter = NULL,
445 data_(data + offset),
446 length_(strlen(data) - offset),
449 ~TestOneByteResource() {
450 i::DeleteArray(orig_data_);
451 if (counter_ != NULL) ++*counter_;
454 const char* data() const {
458 size_t length() const {
463 const char* orig_data_;
470 THREADED_TEST(ScriptUsingStringResource) {
471 int dispose_count = 0;
472 const char* c_source = "1 + 2 * 3";
473 uint16_t* two_byte_source = AsciiToTwoByteString(c_source);
476 v8::HandleScope scope(env->GetIsolate());
477 TestResource* resource = new TestResource(two_byte_source, &dispose_count);
478 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
479 Local<Script> script = v8_compile(source);
480 Local<Value> value = script->Run();
481 CHECK(value->IsNumber());
482 CHECK_EQ(7, value->Int32Value());
483 CHECK(source->IsExternal());
485 static_cast<TestResource*>(source->GetExternalStringResource()));
486 String::Encoding encoding = String::UNKNOWN_ENCODING;
487 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
488 source->GetExternalStringResourceBase(&encoding));
489 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
490 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
491 CHECK_EQ(0, dispose_count);
493 CcTest::i_isolate()->compilation_cache()->Clear();
494 CcTest::heap()->CollectAllAvailableGarbage();
495 CHECK_EQ(1, dispose_count);
499 THREADED_TEST(ScriptUsingOneByteStringResource) {
500 int dispose_count = 0;
501 const char* c_source = "1 + 2 * 3";
504 v8::HandleScope scope(env->GetIsolate());
505 TestOneByteResource* resource =
506 new TestOneByteResource(i::StrDup(c_source), &dispose_count);
507 Local<String> source = String::NewExternal(env->GetIsolate(), resource);
508 CHECK(source->IsExternalOneByte());
509 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
510 source->GetExternalOneByteStringResource());
511 String::Encoding encoding = String::UNKNOWN_ENCODING;
512 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource),
513 source->GetExternalStringResourceBase(&encoding));
514 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
515 Local<Script> script = v8_compile(source);
516 Local<Value> value = script->Run();
517 CHECK(value->IsNumber());
518 CHECK_EQ(7, value->Int32Value());
519 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
520 CHECK_EQ(0, dispose_count);
522 CcTest::i_isolate()->compilation_cache()->Clear();
523 CcTest::heap()->CollectAllAvailableGarbage();
524 CHECK_EQ(1, dispose_count);
528 THREADED_TEST(ScriptMakingExternalString) {
529 int dispose_count = 0;
530 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3");
533 v8::HandleScope scope(env->GetIsolate());
534 Local<String> source =
535 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
536 // Trigger GCs so that the newly allocated string moves to old gen.
537 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
538 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
539 CHECK_EQ(source->IsExternal(), false);
540 CHECK_EQ(source->IsExternalOneByte(), false);
541 String::Encoding encoding = String::UNKNOWN_ENCODING;
542 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding));
543 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
544 bool success = source->MakeExternal(new TestResource(two_byte_source,
547 Local<Script> script = v8_compile(source);
548 Local<Value> value = script->Run();
549 CHECK(value->IsNumber());
550 CHECK_EQ(7, value->Int32Value());
551 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
552 CHECK_EQ(0, dispose_count);
554 CcTest::i_isolate()->compilation_cache()->Clear();
555 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
556 CHECK_EQ(1, dispose_count);
560 THREADED_TEST(ScriptMakingExternalOneByteString) {
561 int dispose_count = 0;
562 const char* c_source = "1 + 2 * 3";
565 v8::HandleScope scope(env->GetIsolate());
566 Local<String> source = v8_str(c_source);
567 // Trigger GCs so that the newly allocated string moves to old gen.
568 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
569 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
570 bool success = source->MakeExternal(
571 new TestOneByteResource(i::StrDup(c_source), &dispose_count));
573 Local<Script> script = v8_compile(source);
574 Local<Value> value = script->Run();
575 CHECK(value->IsNumber());
576 CHECK_EQ(7, value->Int32Value());
577 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
578 CHECK_EQ(0, dispose_count);
580 CcTest::i_isolate()->compilation_cache()->Clear();
581 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
582 CHECK_EQ(1, dispose_count);
586 TEST(MakingExternalStringConditions) {
588 v8::HandleScope scope(env->GetIsolate());
590 // Free some space in the new space so that we can check freshness.
591 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
592 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
594 uint16_t* two_byte_string = AsciiToTwoByteString("s1");
595 Local<String> small_string =
596 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
597 i::DeleteArray(two_byte_string);
599 // We should refuse to externalize newly created small string.
600 CHECK(!small_string->CanMakeExternal());
601 // Trigger GCs so that the newly allocated string moves to old gen.
602 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
603 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
604 // Old space strings should be accepted.
605 CHECK(small_string->CanMakeExternal());
607 two_byte_string = AsciiToTwoByteString("small string 2");
608 small_string = String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
609 i::DeleteArray(two_byte_string);
611 // We should refuse externalizing newly created small string.
612 CHECK(!small_string->CanMakeExternal());
613 for (int i = 0; i < 100; i++) {
614 String::Value value(small_string);
616 // Frequently used strings should be accepted.
617 CHECK(small_string->CanMakeExternal());
619 const int buf_size = 10 * 1024;
620 char* buf = i::NewArray<char>(buf_size);
621 memset(buf, 'a', buf_size);
622 buf[buf_size - 1] = '\0';
624 two_byte_string = AsciiToTwoByteString(buf);
625 Local<String> large_string =
626 String::NewFromTwoByte(env->GetIsolate(), two_byte_string);
628 i::DeleteArray(two_byte_string);
629 // Large strings should be immediately accepted.
630 CHECK(large_string->CanMakeExternal());
634 TEST(MakingExternalOneByteStringConditions) {
636 v8::HandleScope scope(env->GetIsolate());
638 // Free some space in the new space so that we can check freshness.
639 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
640 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
642 Local<String> small_string = String::NewFromUtf8(env->GetIsolate(), "s1");
643 // We should refuse to externalize newly created small string.
644 CHECK(!small_string->CanMakeExternal());
645 // Trigger GCs so that the newly allocated string moves to old gen.
646 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
647 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
648 // Old space strings should be accepted.
649 CHECK(small_string->CanMakeExternal());
651 small_string = String::NewFromUtf8(env->GetIsolate(), "small string 2");
652 // We should refuse externalizing newly created small string.
653 CHECK(!small_string->CanMakeExternal());
654 for (int i = 0; i < 100; i++) {
655 String::Value value(small_string);
657 // Frequently used strings should be accepted.
658 CHECK(small_string->CanMakeExternal());
660 const int buf_size = 10 * 1024;
661 char* buf = i::NewArray<char>(buf_size);
662 memset(buf, 'a', buf_size);
663 buf[buf_size - 1] = '\0';
664 Local<String> large_string = String::NewFromUtf8(env->GetIsolate(), buf);
666 // Large strings should be immediately accepted.
667 CHECK(large_string->CanMakeExternal());
671 TEST(MakingExternalUnalignedOneByteString) {
673 v8::HandleScope scope(env->GetIsolate());
675 CompileRun("function cons(a, b) { return a + b; }"
676 "function slice(a) { return a.substring(1); }");
677 // Create a cons string that will land in old pointer space.
678 Local<String> cons = Local<String>::Cast(CompileRun(
679 "cons('abcdefghijklm', 'nopqrstuvwxyz');"));
680 // Create a sliced string that will land in old pointer space.
681 Local<String> slice = Local<String>::Cast(CompileRun(
682 "slice('abcdefghijklmnopqrstuvwxyz');"));
684 // Trigger GCs so that the newly allocated string moves to old gen.
685 SimulateFullSpace(CcTest::heap()->old_pointer_space());
686 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
687 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
689 // Turn into external string with unaligned resource data.
690 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz";
692 cons->MakeExternal(new TestOneByteResource(i::StrDup(c_cons), NULL, 1));
694 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz";
696 slice->MakeExternal(new TestOneByteResource(i::StrDup(c_slice), NULL, 1));
699 // Trigger GCs and force evacuation.
700 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
701 CcTest::heap()->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask);
705 THREADED_TEST(UsingExternalString) {
706 i::Factory* factory = CcTest::i_isolate()->factory();
708 v8::HandleScope scope(CcTest::isolate());
709 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
710 Local<String> string = String::NewExternal(
711 CcTest::isolate(), new TestResource(two_byte_string));
712 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
713 // Trigger GCs so that the newly allocated string moves to old gen.
714 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
715 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
716 i::Handle<i::String> isymbol =
717 factory->InternalizeString(istring);
718 CHECK(isymbol->IsInternalizedString());
720 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
721 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
725 THREADED_TEST(UsingExternalOneByteString) {
726 i::Factory* factory = CcTest::i_isolate()->factory();
728 v8::HandleScope scope(CcTest::isolate());
729 const char* one_byte_string = "test string";
730 Local<String> string = String::NewExternal(
731 CcTest::isolate(), new TestOneByteResource(i::StrDup(one_byte_string)));
732 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
733 // Trigger GCs so that the newly allocated string moves to old gen.
734 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in survivor space now
735 CcTest::heap()->CollectGarbage(i::NEW_SPACE); // in old gen now
736 i::Handle<i::String> isymbol =
737 factory->InternalizeString(istring);
738 CHECK(isymbol->IsInternalizedString());
740 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
741 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
745 class DummyResource : public v8::String::ExternalStringResource {
747 virtual const uint16_t* data() const { return string_; }
748 virtual size_t length() const { return 1 << 30; }
751 uint16_t string_[10];
755 class DummyOneByteResource : public v8::String::ExternalOneByteStringResource {
757 virtual const char* data() const { return string_; }
758 virtual size_t length() const { return 1 << 30; }
765 THREADED_TEST(NewExternalForVeryLongString) {
768 v8::HandleScope scope(env->GetIsolate());
769 v8::TryCatch try_catch;
770 DummyOneByteResource r;
771 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
772 CHECK(str.IsEmpty());
773 CHECK(try_catch.HasCaught());
774 String::Utf8Value exception_value(try_catch.Exception());
775 CHECK_EQ("RangeError: Invalid string length", *exception_value);
780 v8::HandleScope scope(env->GetIsolate());
781 v8::TryCatch try_catch;
783 v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
784 CHECK(str.IsEmpty());
785 CHECK(try_catch.HasCaught());
786 String::Utf8Value exception_value(try_catch.Exception());
787 CHECK_EQ("RangeError: Invalid string length", *exception_value);
792 THREADED_TEST(ScavengeExternalString) {
793 i::FLAG_stress_compaction = false;
794 i::FLAG_gc_global = false;
795 int dispose_count = 0;
796 bool in_new_space = false;
798 v8::HandleScope scope(CcTest::isolate());
799 uint16_t* two_byte_string = AsciiToTwoByteString("test string");
800 Local<String> string = String::NewExternal(
801 CcTest::isolate(), new TestResource(two_byte_string, &dispose_count));
802 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
803 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
804 in_new_space = CcTest::heap()->InNewSpace(*istring);
805 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
806 CHECK_EQ(0, dispose_count);
808 CcTest::heap()->CollectGarbage(
809 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
810 CHECK_EQ(1, dispose_count);
814 THREADED_TEST(ScavengeExternalOneByteString) {
815 i::FLAG_stress_compaction = false;
816 i::FLAG_gc_global = false;
817 int dispose_count = 0;
818 bool in_new_space = false;
820 v8::HandleScope scope(CcTest::isolate());
821 const char* one_byte_string = "test string";
822 Local<String> string = String::NewExternal(
824 new TestOneByteResource(i::StrDup(one_byte_string), &dispose_count));
825 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string);
826 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
827 in_new_space = CcTest::heap()->InNewSpace(*istring);
828 CHECK(in_new_space || CcTest::heap()->old_data_space()->Contains(*istring));
829 CHECK_EQ(0, dispose_count);
831 CcTest::heap()->CollectGarbage(
832 in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE);
833 CHECK_EQ(1, dispose_count);
837 class TestOneByteResourceWithDisposeControl : public TestOneByteResource {
839 // Only used by non-threaded tests, so it can use static fields.
840 static int dispose_calls;
841 static int dispose_count;
843 TestOneByteResourceWithDisposeControl(const char* data, bool dispose)
844 : TestOneByteResource(data, &dispose_count), dispose_(dispose) {}
848 if (dispose_) delete this;
855 int TestOneByteResourceWithDisposeControl::dispose_count = 0;
856 int TestOneByteResourceWithDisposeControl::dispose_calls = 0;
859 TEST(ExternalStringWithDisposeHandling) {
860 const char* c_source = "1 + 2 * 3";
862 // Use a stack allocated external string resource allocated object.
863 TestOneByteResourceWithDisposeControl::dispose_count = 0;
864 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
865 TestOneByteResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
868 v8::HandleScope scope(env->GetIsolate());
869 Local<String> source = String::NewExternal(env->GetIsolate(), &res_stack);
870 Local<Script> script = v8_compile(source);
871 Local<Value> value = script->Run();
872 CHECK(value->IsNumber());
873 CHECK_EQ(7, value->Int32Value());
874 CcTest::heap()->CollectAllAvailableGarbage();
875 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
877 CcTest::i_isolate()->compilation_cache()->Clear();
878 CcTest::heap()->CollectAllAvailableGarbage();
879 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
880 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
882 // Use a heap allocated external string resource allocated object.
883 TestOneByteResourceWithDisposeControl::dispose_count = 0;
884 TestOneByteResourceWithDisposeControl::dispose_calls = 0;
885 TestOneByteResource* res_heap =
886 new TestOneByteResourceWithDisposeControl(i::StrDup(c_source), true);
889 v8::HandleScope scope(env->GetIsolate());
890 Local<String> source = String::NewExternal(env->GetIsolate(), res_heap);
891 Local<Script> script = v8_compile(source);
892 Local<Value> value = script->Run();
893 CHECK(value->IsNumber());
894 CHECK_EQ(7, value->Int32Value());
895 CcTest::heap()->CollectAllAvailableGarbage();
896 CHECK_EQ(0, TestOneByteResourceWithDisposeControl::dispose_count);
898 CcTest::i_isolate()->compilation_cache()->Clear();
899 CcTest::heap()->CollectAllAvailableGarbage();
900 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_calls);
901 CHECK_EQ(1, TestOneByteResourceWithDisposeControl::dispose_count);
905 THREADED_TEST(StringConcat) {
908 v8::HandleScope scope(env->GetIsolate());
909 const char* one_byte_string_1 = "function a_times_t";
910 const char* two_byte_string_1 = "wo_plus_b(a, b) {return ";
911 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + ";
912 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + ";
913 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
914 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + ";
915 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);";
916 Local<String> left = v8_str(one_byte_string_1);
918 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1);
919 Local<String> right =
920 String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
921 i::DeleteArray(two_byte_source);
923 Local<String> source = String::Concat(left, right);
924 right = String::NewExternal(
926 new TestOneByteResource(i::StrDup(one_byte_extern_1)));
927 source = String::Concat(source, right);
928 right = String::NewExternal(
930 new TestResource(AsciiToTwoByteString(two_byte_extern_1)));
931 source = String::Concat(source, right);
932 right = v8_str(one_byte_string_2);
933 source = String::Concat(source, right);
935 two_byte_source = AsciiToTwoByteString(two_byte_string_2);
936 right = String::NewFromTwoByte(env->GetIsolate(), two_byte_source);
937 i::DeleteArray(two_byte_source);
939 source = String::Concat(source, right);
940 right = String::NewExternal(
942 new TestResource(AsciiToTwoByteString(two_byte_extern_2)));
943 source = String::Concat(source, right);
944 Local<Script> script = v8_compile(source);
945 Local<Value> value = script->Run();
946 CHECK(value->IsNumber());
947 CHECK_EQ(68, value->Int32Value());
949 CcTest::i_isolate()->compilation_cache()->Clear();
950 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
951 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
955 THREADED_TEST(GlobalProperties) {
957 v8::HandleScope scope(env->GetIsolate());
958 v8::Handle<v8::Object> global = env->Global();
959 global->Set(v8_str("pi"), v8_num(3.1415926));
960 Local<Value> pi = global->Get(v8_str("pi"));
961 CHECK_EQ(3.1415926, pi->NumberValue());
966 static void CheckReturnValue(const T& t, i::Address callback) {
967 v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
968 i::Object** o = *reinterpret_cast<i::Object***>(&rv);
969 CHECK_EQ(CcTest::isolate(), t.GetIsolate());
970 CHECK_EQ(t.GetIsolate(), rv.GetIsolate());
971 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
973 bool is_runtime = (*o)->IsTheHole();
975 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined());
976 rv.Set(v8::Handle<v8::Object>());
977 CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
978 CHECK_EQ(is_runtime, (*o)->IsTheHole());
980 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
981 // If CPU profiler is active check that when API callback is invoked
982 // VMState is set to EXTERNAL.
983 if (isolate->cpu_profiler()->is_profiling()) {
984 CHECK_EQ(v8::EXTERNAL, isolate->current_vm_state());
985 CHECK(isolate->external_callback_scope());
986 CHECK_EQ(callback, isolate->external_callback_scope()->callback());
991 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
992 i::Address callback) {
993 ApiTestFuzzer::Fuzz();
994 CheckReturnValue(info, callback);
995 info.GetReturnValue().Set(v8_str("bad value"));
996 info.GetReturnValue().Set(v8_num(102));
1000 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
1001 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
1005 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
1006 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
1009 static void construct_callback(
1010 const v8::FunctionCallbackInfo<Value>& info) {
1011 ApiTestFuzzer::Fuzz();
1012 CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
1013 info.This()->Set(v8_str("x"), v8_num(1));
1014 info.This()->Set(v8_str("y"), v8_num(2));
1015 info.GetReturnValue().Set(v8_str("bad value"));
1016 info.GetReturnValue().Set(info.This());
1020 static void Return239Callback(
1021 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
1022 ApiTestFuzzer::Fuzz();
1023 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
1024 info.GetReturnValue().Set(v8_str("bad value"));
1025 info.GetReturnValue().Set(v8_num(239));
1029 template<typename Handler>
1030 static void TestFunctionTemplateInitializer(Handler handler,
1031 Handler handler_2) {
1032 // Test constructor calls.
1035 v8::Isolate* isolate = env->GetIsolate();
1036 v8::HandleScope scope(isolate);
1038 Local<v8::FunctionTemplate> fun_templ =
1039 v8::FunctionTemplate::New(isolate, handler);
1040 Local<Function> fun = fun_templ->GetFunction();
1041 env->Global()->Set(v8_str("obj"), fun);
1042 Local<Script> script = v8_compile("obj()");
1043 for (int i = 0; i < 30; i++) {
1044 CHECK_EQ(102, script->Run()->Int32Value());
1047 // Use SetCallHandler to initialize a function template, should work like
1048 // the previous one.
1051 v8::Isolate* isolate = env->GetIsolate();
1052 v8::HandleScope scope(isolate);
1054 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
1055 fun_templ->SetCallHandler(handler_2);
1056 Local<Function> fun = fun_templ->GetFunction();
1057 env->Global()->Set(v8_str("obj"), fun);
1058 Local<Script> script = v8_compile("obj()");
1059 for (int i = 0; i < 30; i++) {
1060 CHECK_EQ(102, script->Run()->Int32Value());
1066 template<typename Constructor, typename Accessor>
1067 static void TestFunctionTemplateAccessor(Constructor constructor,
1068 Accessor accessor) {
1070 v8::HandleScope scope(env->GetIsolate());
1072 Local<v8::FunctionTemplate> fun_templ =
1073 v8::FunctionTemplate::New(env->GetIsolate(), constructor);
1074 fun_templ->SetClassName(v8_str("funky"));
1075 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
1076 Local<Function> fun = fun_templ->GetFunction();
1077 env->Global()->Set(v8_str("obj"), fun);
1078 Local<Value> result = v8_compile("(new obj()).toString()")->Run();
1079 CHECK_EQ(v8_str("[object funky]"), result);
1080 CompileRun("var obj_instance = new obj();");
1081 Local<Script> script;
1082 script = v8_compile("obj_instance.x");
1083 for (int i = 0; i < 30; i++) {
1084 CHECK_EQ(1, script->Run()->Int32Value());
1086 script = v8_compile("obj_instance.m");
1087 for (int i = 0; i < 30; i++) {
1088 CHECK_EQ(239, script->Run()->Int32Value());
1093 THREADED_PROFILED_TEST(FunctionTemplate) {
1094 TestFunctionTemplateInitializer(handle_callback, handle_callback_2);
1095 TestFunctionTemplateAccessor(construct_callback, Return239Callback);
1099 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
1100 ApiTestFuzzer::Fuzz();
1101 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
1102 info.GetReturnValue().Set(v8_num(51423 + info.Length()));
1106 template<typename Callback>
1107 static void TestSimpleCallback(Callback callback) {
1109 v8::Isolate* isolate = env->GetIsolate();
1110 v8::HandleScope scope(isolate);
1112 v8::Handle<v8::ObjectTemplate> object_template =
1113 v8::ObjectTemplate::New(isolate);
1114 object_template->Set(isolate, "callback",
1115 v8::FunctionTemplate::New(isolate, callback));
1116 v8::Local<v8::Object> object = object_template->NewInstance();
1117 (*env)->Global()->Set(v8_str("callback_object"), object);
1118 v8::Handle<v8::Script> script;
1119 script = v8_compile("callback_object.callback(17)");
1120 for (int i = 0; i < 30; i++) {
1121 CHECK_EQ(51424, script->Run()->Int32Value());
1123 script = v8_compile("callback_object.callback(17, 24)");
1124 for (int i = 0; i < 30; i++) {
1125 CHECK_EQ(51425, script->Run()->Int32Value());
1130 THREADED_PROFILED_TEST(SimpleCallback) {
1131 TestSimpleCallback(SimpleCallback);
1135 template<typename T>
1136 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
1138 // constant return values
1139 static int32_t fast_return_value_int32 = 471;
1140 static uint32_t fast_return_value_uint32 = 571;
1141 static const double kFastReturnValueDouble = 2.7;
1142 // variable return values
1143 static bool fast_return_value_bool = false;
1144 enum ReturnValueOddball {
1146 kUndefinedReturnValue,
1147 kEmptyStringReturnValue
1149 static ReturnValueOddball fast_return_value_void;
1150 static bool fast_return_value_object_is_empty = false;
1152 // Helper function to avoid compiler error: insufficient contextual information
1153 // to determine type when applying FUNCTION_ADDR to a template function.
1154 static i::Address address_of(v8::FunctionCallback callback) {
1155 return FUNCTION_ADDR(callback);
1159 void FastReturnValueCallback<int32_t>(
1160 const v8::FunctionCallbackInfo<v8::Value>& info) {
1161 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>));
1162 info.GetReturnValue().Set(fast_return_value_int32);
1166 void FastReturnValueCallback<uint32_t>(
1167 const v8::FunctionCallbackInfo<v8::Value>& info) {
1168 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>));
1169 info.GetReturnValue().Set(fast_return_value_uint32);
1173 void FastReturnValueCallback<double>(
1174 const v8::FunctionCallbackInfo<v8::Value>& info) {
1175 CheckReturnValue(info, address_of(FastReturnValueCallback<double>));
1176 info.GetReturnValue().Set(kFastReturnValueDouble);
1180 void FastReturnValueCallback<bool>(
1181 const v8::FunctionCallbackInfo<v8::Value>& info) {
1182 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>));
1183 info.GetReturnValue().Set(fast_return_value_bool);
1187 void FastReturnValueCallback<void>(
1188 const v8::FunctionCallbackInfo<v8::Value>& info) {
1189 CheckReturnValue(info, address_of(FastReturnValueCallback<void>));
1190 switch (fast_return_value_void) {
1191 case kNullReturnValue:
1192 info.GetReturnValue().SetNull();
1194 case kUndefinedReturnValue:
1195 info.GetReturnValue().SetUndefined();
1197 case kEmptyStringReturnValue:
1198 info.GetReturnValue().SetEmptyString();
1204 void FastReturnValueCallback<Object>(
1205 const v8::FunctionCallbackInfo<v8::Value>& info) {
1206 v8::Handle<v8::Object> object;
1207 if (!fast_return_value_object_is_empty) {
1208 object = Object::New(info.GetIsolate());
1210 info.GetReturnValue().Set(object);
1213 template<typename T>
1214 Handle<Value> TestFastReturnValues() {
1216 v8::Isolate* isolate = env->GetIsolate();
1217 v8::EscapableHandleScope scope(isolate);
1218 v8::Handle<v8::ObjectTemplate> object_template =
1219 v8::ObjectTemplate::New(isolate);
1220 v8::FunctionCallback callback = &FastReturnValueCallback<T>;
1221 object_template->Set(isolate, "callback",
1222 v8::FunctionTemplate::New(isolate, callback));
1223 v8::Local<v8::Object> object = object_template->NewInstance();
1224 (*env)->Global()->Set(v8_str("callback_object"), object);
1225 return scope.Escape(CompileRun("callback_object.callback()"));
1229 THREADED_PROFILED_TEST(FastReturnValues) {
1231 v8::HandleScope scope(CcTest::isolate());
1232 v8::Handle<v8::Value> value;
1233 // check int32_t and uint32_t
1234 int32_t int_values[] = {
1236 i::Smi::kMinValue, i::Smi::kMaxValue
1238 for (size_t i = 0; i < arraysize(int_values); i++) {
1239 for (int modifier = -1; modifier <= 1; modifier++) {
1240 int int_value = int_values[i] + modifier;
1242 fast_return_value_int32 = int_value;
1243 value = TestFastReturnValues<int32_t>();
1244 CHECK(value->IsInt32());
1245 CHECK(fast_return_value_int32 == value->Int32Value());
1247 fast_return_value_uint32 = static_cast<uint32_t>(int_value);
1248 value = TestFastReturnValues<uint32_t>();
1249 CHECK(value->IsUint32());
1250 CHECK(fast_return_value_uint32 == value->Uint32Value());
1254 value = TestFastReturnValues<double>();
1255 CHECK(value->IsNumber());
1256 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
1257 // check bool values
1258 for (int i = 0; i < 2; i++) {
1259 fast_return_value_bool = i == 0;
1260 value = TestFastReturnValues<bool>();
1261 CHECK(value->IsBoolean());
1262 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
1265 ReturnValueOddball oddballs[] = {
1267 kUndefinedReturnValue,
1268 kEmptyStringReturnValue
1270 for (size_t i = 0; i < arraysize(oddballs); i++) {
1271 fast_return_value_void = oddballs[i];
1272 value = TestFastReturnValues<void>();
1273 switch (fast_return_value_void) {
1274 case kNullReturnValue:
1275 CHECK(value->IsNull());
1277 case kUndefinedReturnValue:
1278 CHECK(value->IsUndefined());
1280 case kEmptyStringReturnValue:
1281 CHECK(value->IsString());
1282 CHECK_EQ(0, v8::String::Cast(*value)->Length());
1287 fast_return_value_object_is_empty = false;
1288 value = TestFastReturnValues<Object>();
1289 CHECK(value->IsObject());
1290 fast_return_value_object_is_empty = true;
1291 value = TestFastReturnValues<Object>();
1292 CHECK(value->IsUndefined());
1296 THREADED_TEST(FunctionTemplateSetLength) {
1298 v8::Isolate* isolate = env->GetIsolate();
1299 v8::HandleScope scope(isolate);
1301 Local<v8::FunctionTemplate> fun_templ =
1302 v8::FunctionTemplate::New(isolate,
1304 Handle<v8::Value>(),
1305 Handle<v8::Signature>(),
1307 Local<Function> fun = fun_templ->GetFunction();
1308 env->Global()->Set(v8_str("obj"), fun);
1309 Local<Script> script = v8_compile("obj.length");
1310 CHECK_EQ(23, script->Run()->Int32Value());
1313 Local<v8::FunctionTemplate> fun_templ =
1314 v8::FunctionTemplate::New(isolate, handle_callback);
1315 fun_templ->SetLength(22);
1316 Local<Function> fun = fun_templ->GetFunction();
1317 env->Global()->Set(v8_str("obj"), fun);
1318 Local<Script> script = v8_compile("obj.length");
1319 CHECK_EQ(22, script->Run()->Int32Value());
1322 // Without setting length it defaults to 0.
1323 Local<v8::FunctionTemplate> fun_templ =
1324 v8::FunctionTemplate::New(isolate, handle_callback);
1325 Local<Function> fun = fun_templ->GetFunction();
1326 env->Global()->Set(v8_str("obj"), fun);
1327 Local<Script> script = v8_compile("obj.length");
1328 CHECK_EQ(0, script->Run()->Int32Value());
1333 static void* expected_ptr;
1334 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) {
1335 void* ptr = v8::External::Cast(*args.Data())->Value();
1336 CHECK_EQ(expected_ptr, ptr);
1337 args.GetReturnValue().Set(true);
1341 static void TestExternalPointerWrapping() {
1343 v8::Isolate* isolate = env->GetIsolate();
1344 v8::HandleScope scope(isolate);
1346 v8::Handle<v8::Value> data =
1347 v8::External::New(isolate, expected_ptr);
1349 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
1350 obj->Set(v8_str("func"),
1351 v8::FunctionTemplate::New(isolate, callback, data)->GetFunction());
1352 env->Global()->Set(v8_str("obj"), obj);
1355 "function foo() {\n"
1356 " for (var i = 0; i < 13; i++) obj.func();\n"
1358 "foo(), true")->BooleanValue());
1362 THREADED_TEST(ExternalWrap) {
1363 // Check heap allocated object.
1366 TestExternalPointerWrapping();
1369 // Check stack allocated object.
1371 expected_ptr = &foo;
1372 TestExternalPointerWrapping();
1374 // Check not aligned addresses.
1376 char* s = new char[n];
1377 for (int i = 0; i < n; i++) {
1378 expected_ptr = s + i;
1379 TestExternalPointerWrapping();
1384 // Check several invalid addresses.
1385 expected_ptr = reinterpret_cast<void*>(1);
1386 TestExternalPointerWrapping();
1388 expected_ptr = reinterpret_cast<void*>(0xdeadbeef);
1389 TestExternalPointerWrapping();
1391 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1);
1392 TestExternalPointerWrapping();
1394 #if defined(V8_HOST_ARCH_X64)
1395 // Check a value with a leading 1 bit in x64 Smi encoding.
1396 expected_ptr = reinterpret_cast<void*>(0x400000000);
1397 TestExternalPointerWrapping();
1399 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef);
1400 TestExternalPointerWrapping();
1402 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1);
1403 TestExternalPointerWrapping();
1408 THREADED_TEST(FindInstanceInPrototypeChain) {
1410 v8::Isolate* isolate = env->GetIsolate();
1411 v8::HandleScope scope(isolate);
1413 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(isolate);
1414 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(isolate);
1415 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(isolate);
1416 derived->Inherit(base);
1418 Local<v8::Function> base_function = base->GetFunction();
1419 Local<v8::Function> derived_function = derived->GetFunction();
1420 Local<v8::Function> other_function = other->GetFunction();
1422 Local<v8::Object> base_instance = base_function->NewInstance();
1423 Local<v8::Object> derived_instance = derived_function->NewInstance();
1424 Local<v8::Object> derived_instance2 = derived_function->NewInstance();
1425 Local<v8::Object> other_instance = other_function->NewInstance();
1426 derived_instance2->Set(v8_str("__proto__"), derived_instance);
1427 other_instance->Set(v8_str("__proto__"), derived_instance2);
1429 // base_instance is only an instance of base.
1430 CHECK_EQ(base_instance,
1431 base_instance->FindInstanceInPrototypeChain(base));
1432 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty());
1433 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1435 // derived_instance is an instance of base and derived.
1436 CHECK_EQ(derived_instance,
1437 derived_instance->FindInstanceInPrototypeChain(base));
1438 CHECK_EQ(derived_instance,
1439 derived_instance->FindInstanceInPrototypeChain(derived));
1440 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty());
1442 // other_instance is an instance of other and its immediate
1443 // prototype derived_instance2 is an instance of base and derived.
1444 // Note, derived_instance is an instance of base and derived too,
1445 // but it comes after derived_instance2 in the prototype chain of
1447 CHECK_EQ(derived_instance2,
1448 other_instance->FindInstanceInPrototypeChain(base));
1449 CHECK_EQ(derived_instance2,
1450 other_instance->FindInstanceInPrototypeChain(derived));
1451 CHECK_EQ(other_instance,
1452 other_instance->FindInstanceInPrototypeChain(other));
1456 THREADED_TEST(TinyInteger) {
1458 v8::Isolate* isolate = env->GetIsolate();
1459 v8::HandleScope scope(isolate);
1461 int32_t value = 239;
1462 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1463 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1465 value_obj = v8::Integer::New(isolate, value);
1466 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1470 THREADED_TEST(BigSmiInteger) {
1472 v8::HandleScope scope(env->GetIsolate());
1473 v8::Isolate* isolate = CcTest::isolate();
1475 int32_t value = i::Smi::kMaxValue;
1476 // We cannot add one to a Smi::kMaxValue without wrapping.
1477 if (i::SmiValuesAre31Bits()) {
1478 CHECK(i::Smi::IsValid(value));
1479 CHECK(!i::Smi::IsValid(value + 1));
1481 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1482 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1484 value_obj = v8::Integer::New(isolate, value);
1485 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1490 THREADED_TEST(BigInteger) {
1492 v8::HandleScope scope(env->GetIsolate());
1493 v8::Isolate* isolate = CcTest::isolate();
1495 // We cannot add one to a Smi::kMaxValue without wrapping.
1496 if (i::SmiValuesAre31Bits()) {
1497 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1.
1498 // The code will not be run in that case, due to the "if" guard.
1500 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1);
1501 CHECK(value > i::Smi::kMaxValue);
1502 CHECK(!i::Smi::IsValid(value));
1504 Local<v8::Integer> value_obj = v8::Integer::New(isolate, value);
1505 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1507 value_obj = v8::Integer::New(isolate, value);
1508 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1513 THREADED_TEST(TinyUnsignedInteger) {
1515 v8::HandleScope scope(env->GetIsolate());
1516 v8::Isolate* isolate = CcTest::isolate();
1518 uint32_t value = 239;
1520 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1521 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1523 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1524 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1528 THREADED_TEST(BigUnsignedSmiInteger) {
1530 v8::HandleScope scope(env->GetIsolate());
1531 v8::Isolate* isolate = CcTest::isolate();
1533 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue);
1534 CHECK(i::Smi::IsValid(value));
1535 CHECK(!i::Smi::IsValid(value + 1));
1537 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1538 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1540 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1541 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1545 THREADED_TEST(BigUnsignedInteger) {
1547 v8::HandleScope scope(env->GetIsolate());
1548 v8::Isolate* isolate = CcTest::isolate();
1550 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1;
1551 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue));
1552 CHECK(!i::Smi::IsValid(value));
1554 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1555 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1557 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1558 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1562 THREADED_TEST(OutOfSignedRangeUnsignedInteger) {
1564 v8::HandleScope scope(env->GetIsolate());
1565 v8::Isolate* isolate = CcTest::isolate();
1567 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1;
1568 uint32_t value = INT32_MAX_AS_UINT + 1;
1569 CHECK(value > INT32_MAX_AS_UINT); // No overflow.
1571 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1572 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1574 value_obj = v8::Integer::NewFromUnsigned(isolate, value);
1575 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value());
1579 THREADED_TEST(IsNativeError) {
1581 v8::HandleScope scope(env->GetIsolate());
1582 v8::Handle<Value> syntax_error = CompileRun(
1583 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; ");
1584 CHECK(syntax_error->IsNativeError());
1585 v8::Handle<Value> not_error = CompileRun("{a:42}");
1586 CHECK(!not_error->IsNativeError());
1587 v8::Handle<Value> not_object = CompileRun("42");
1588 CHECK(!not_object->IsNativeError());
1592 THREADED_TEST(IsGeneratorFunctionOrObject) {
1594 v8::HandleScope scope(env->GetIsolate());
1596 CompileRun("function *gen() { yield 1; }\nfunction func() {}");
1597 v8::Handle<Value> gen = CompileRun("gen");
1598 v8::Handle<Value> genObj = CompileRun("gen()");
1599 v8::Handle<Value> object = CompileRun("{a:42}");
1600 v8::Handle<Value> func = CompileRun("func");
1602 CHECK(gen->IsGeneratorFunction());
1603 CHECK(gen->IsFunction());
1604 CHECK(!gen->IsGeneratorObject());
1606 CHECK(!genObj->IsGeneratorFunction());
1607 CHECK(!genObj->IsFunction());
1608 CHECK(genObj->IsGeneratorObject());
1610 CHECK(!object->IsGeneratorFunction());
1611 CHECK(!object->IsFunction());
1612 CHECK(!object->IsGeneratorObject());
1614 CHECK(!func->IsGeneratorFunction());
1615 CHECK(func->IsFunction());
1616 CHECK(!func->IsGeneratorObject());
1620 THREADED_TEST(ArgumentsObject) {
1622 v8::HandleScope scope(env->GetIsolate());
1623 v8::Handle<Value> arguments_object =
1624 CompileRun("var out = 0; (function(){ out = arguments; })(1,2,3); out;");
1625 CHECK(arguments_object->IsArgumentsObject());
1626 v8::Handle<Value> array = CompileRun("[1,2,3]");
1627 CHECK(!array->IsArgumentsObject());
1628 v8::Handle<Value> object = CompileRun("{a:42}");
1629 CHECK(!object->IsArgumentsObject());
1633 THREADED_TEST(IsMapOrSet) {
1635 v8::HandleScope scope(env->GetIsolate());
1636 v8::Handle<Value> map = CompileRun("new Map()");
1637 v8::Handle<Value> set = CompileRun("new Set()");
1638 v8::Handle<Value> weak_map = CompileRun("new WeakMap()");
1639 v8::Handle<Value> weak_set = CompileRun("new WeakSet()");
1640 CHECK(map->IsMap());
1641 CHECK(set->IsSet());
1642 CHECK(weak_map->IsWeakMap());
1643 CHECK(weak_set->IsWeakSet());
1645 CHECK(!map->IsSet());
1646 CHECK(!map->IsWeakMap());
1647 CHECK(!map->IsWeakSet());
1649 CHECK(!set->IsMap());
1650 CHECK(!set->IsWeakMap());
1651 CHECK(!set->IsWeakSet());
1653 CHECK(!weak_map->IsMap());
1654 CHECK(!weak_map->IsSet());
1655 CHECK(!weak_map->IsWeakSet());
1657 CHECK(!weak_set->IsMap());
1658 CHECK(!weak_set->IsSet());
1659 CHECK(!weak_set->IsWeakMap());
1661 v8::Handle<Value> object = CompileRun("{a:42}");
1662 CHECK(!object->IsMap());
1663 CHECK(!object->IsSet());
1664 CHECK(!object->IsWeakMap());
1665 CHECK(!object->IsWeakSet());
1669 THREADED_TEST(StringObject) {
1671 v8::HandleScope scope(env->GetIsolate());
1672 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")");
1673 CHECK(boxed_string->IsStringObject());
1674 v8::Handle<Value> unboxed_string = CompileRun("\"test\"");
1675 CHECK(!unboxed_string->IsStringObject());
1676 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)");
1677 CHECK(!boxed_not_string->IsStringObject());
1678 v8::Handle<Value> not_object = CompileRun("0");
1679 CHECK(!not_object->IsStringObject());
1680 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>();
1681 CHECK(!as_boxed.IsEmpty());
1682 Local<v8::String> the_string = as_boxed->ValueOf();
1683 CHECK(!the_string.IsEmpty());
1684 ExpectObject("\"test\"", the_string);
1685 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string);
1686 CHECK(new_boxed_string->IsStringObject());
1687 as_boxed = new_boxed_string.As<v8::StringObject>();
1688 the_string = as_boxed->ValueOf();
1689 CHECK(!the_string.IsEmpty());
1690 ExpectObject("\"test\"", the_string);
1694 THREADED_TEST(NumberObject) {
1696 v8::HandleScope scope(env->GetIsolate());
1697 v8::Handle<Value> boxed_number = CompileRun("new Number(42)");
1698 CHECK(boxed_number->IsNumberObject());
1699 v8::Handle<Value> unboxed_number = CompileRun("42");
1700 CHECK(!unboxed_number->IsNumberObject());
1701 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)");
1702 CHECK(!boxed_not_number->IsNumberObject());
1703 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>();
1704 CHECK(!as_boxed.IsEmpty());
1705 double the_number = as_boxed->ValueOf();
1706 CHECK_EQ(42.0, the_number);
1707 v8::Handle<v8::Value> new_boxed_number =
1708 v8::NumberObject::New(env->GetIsolate(), 43);
1709 CHECK(new_boxed_number->IsNumberObject());
1710 as_boxed = new_boxed_number.As<v8::NumberObject>();
1711 the_number = as_boxed->ValueOf();
1712 CHECK_EQ(43.0, the_number);
1716 THREADED_TEST(BooleanObject) {
1718 v8::HandleScope scope(env->GetIsolate());
1719 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)");
1720 CHECK(boxed_boolean->IsBooleanObject());
1721 v8::Handle<Value> unboxed_boolean = CompileRun("true");
1722 CHECK(!unboxed_boolean->IsBooleanObject());
1723 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)");
1724 CHECK(!boxed_not_boolean->IsBooleanObject());
1725 v8::Handle<v8::BooleanObject> as_boxed =
1726 boxed_boolean.As<v8::BooleanObject>();
1727 CHECK(!as_boxed.IsEmpty());
1728 bool the_boolean = as_boxed->ValueOf();
1729 CHECK_EQ(true, the_boolean);
1730 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true);
1731 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false);
1732 CHECK(boxed_true->IsBooleanObject());
1733 CHECK(boxed_false->IsBooleanObject());
1734 as_boxed = boxed_true.As<v8::BooleanObject>();
1735 CHECK_EQ(true, as_boxed->ValueOf());
1736 as_boxed = boxed_false.As<v8::BooleanObject>();
1737 CHECK_EQ(false, as_boxed->ValueOf());
1741 THREADED_TEST(PrimitiveAndWrappedBooleans) {
1743 v8::HandleScope scope(env->GetIsolate());
1745 Local<Value> primitive_false = Boolean::New(env->GetIsolate(), false);
1746 CHECK(primitive_false->IsBoolean());
1747 CHECK(!primitive_false->IsBooleanObject());
1748 CHECK(!primitive_false->BooleanValue());
1749 CHECK(!primitive_false->IsTrue());
1750 CHECK(primitive_false->IsFalse());
1752 Local<Value> false_value = BooleanObject::New(false);
1753 CHECK(!false_value->IsBoolean());
1754 CHECK(false_value->IsBooleanObject());
1755 CHECK(false_value->BooleanValue());
1756 CHECK(!false_value->IsTrue());
1757 CHECK(!false_value->IsFalse());
1759 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>();
1760 CHECK(!false_boolean_object->IsBoolean());
1761 CHECK(false_boolean_object->IsBooleanObject());
1762 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1763 // CHECK(false_boolean_object->BooleanValue());
1764 CHECK(!false_boolean_object->ValueOf());
1765 CHECK(!false_boolean_object->IsTrue());
1766 CHECK(!false_boolean_object->IsFalse());
1768 Local<Value> primitive_true = Boolean::New(env->GetIsolate(), true);
1769 CHECK(primitive_true->IsBoolean());
1770 CHECK(!primitive_true->IsBooleanObject());
1771 CHECK(primitive_true->BooleanValue());
1772 CHECK(primitive_true->IsTrue());
1773 CHECK(!primitive_true->IsFalse());
1775 Local<Value> true_value = BooleanObject::New(true);
1776 CHECK(!true_value->IsBoolean());
1777 CHECK(true_value->IsBooleanObject());
1778 CHECK(true_value->BooleanValue());
1779 CHECK(!true_value->IsTrue());
1780 CHECK(!true_value->IsFalse());
1782 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>();
1783 CHECK(!true_boolean_object->IsBoolean());
1784 CHECK(true_boolean_object->IsBooleanObject());
1785 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted.
1786 // CHECK(true_boolean_object->BooleanValue());
1787 CHECK(true_boolean_object->ValueOf());
1788 CHECK(!true_boolean_object->IsTrue());
1789 CHECK(!true_boolean_object->IsFalse());
1793 THREADED_TEST(Number) {
1795 v8::HandleScope scope(env->GetIsolate());
1796 double PI = 3.1415926;
1797 Local<v8::Number> pi_obj = v8::Number::New(env->GetIsolate(), PI);
1798 CHECK_EQ(PI, pi_obj->NumberValue());
1802 THREADED_TEST(ToNumber) {
1804 v8::Isolate* isolate = CcTest::isolate();
1805 v8::HandleScope scope(isolate);
1806 Local<String> str = v8_str("3.1415926");
1807 CHECK_EQ(3.1415926, str->NumberValue());
1808 v8::Handle<v8::Boolean> t = v8::True(isolate);
1809 CHECK_EQ(1.0, t->NumberValue());
1810 v8::Handle<v8::Boolean> f = v8::False(isolate);
1811 CHECK_EQ(0.0, f->NumberValue());
1815 THREADED_TEST(Date) {
1817 v8::HandleScope scope(env->GetIsolate());
1818 double PI = 3.1415926;
1819 Local<Value> date = v8::Date::New(env->GetIsolate(), PI);
1820 CHECK_EQ(3.0, date->NumberValue());
1821 date.As<v8::Date>()->Set(v8_str("property"),
1822 v8::Integer::New(env->GetIsolate(), 42));
1823 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value());
1827 THREADED_TEST(Boolean) {
1829 v8::Isolate* isolate = env->GetIsolate();
1830 v8::HandleScope scope(isolate);
1831 v8::Handle<v8::Boolean> t = v8::True(isolate);
1833 v8::Handle<v8::Boolean> f = v8::False(isolate);
1835 v8::Handle<v8::Primitive> u = v8::Undefined(isolate);
1836 CHECK(!u->BooleanValue());
1837 v8::Handle<v8::Primitive> n = v8::Null(isolate);
1838 CHECK(!n->BooleanValue());
1839 v8::Handle<String> str1 = v8_str("");
1840 CHECK(!str1->BooleanValue());
1841 v8::Handle<String> str2 = v8_str("x");
1842 CHECK(str2->BooleanValue());
1843 CHECK(!v8::Number::New(isolate, 0)->BooleanValue());
1844 CHECK(v8::Number::New(isolate, -1)->BooleanValue());
1845 CHECK(v8::Number::New(isolate, 1)->BooleanValue());
1846 CHECK(v8::Number::New(isolate, 42)->BooleanValue());
1847 CHECK(!v8_compile("NaN")->Run()->BooleanValue());
1851 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
1852 ApiTestFuzzer::Fuzz();
1853 args.GetReturnValue().Set(v8_num(13.4));
1857 static void GetM(Local<String> name,
1858 const v8::PropertyCallbackInfo<v8::Value>& info) {
1859 ApiTestFuzzer::Fuzz();
1860 info.GetReturnValue().Set(v8_num(876));
1864 THREADED_TEST(GlobalPrototype) {
1865 v8::Isolate* isolate = CcTest::isolate();
1866 v8::HandleScope scope(isolate);
1867 v8::Handle<v8::FunctionTemplate> func_templ =
1868 v8::FunctionTemplate::New(isolate);
1869 func_templ->PrototypeTemplate()->Set(
1870 isolate, "dummy", v8::FunctionTemplate::New(isolate, DummyCallHandler));
1871 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate();
1872 templ->Set(isolate, "x", v8_num(200));
1873 templ->SetAccessor(v8_str("m"), GetM);
1874 LocalContext env(0, templ);
1875 v8::Handle<Script> script(v8_compile("dummy()"));
1876 v8::Handle<Value> result(script->Run());
1877 CHECK_EQ(13.4, result->NumberValue());
1878 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value());
1879 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value());
1883 THREADED_TEST(ObjectTemplate) {
1884 v8::Isolate* isolate = CcTest::isolate();
1885 v8::HandleScope scope(isolate);
1886 Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate);
1887 templ1->Set(isolate, "x", v8_num(10));
1888 templ1->Set(isolate, "y", v8_num(13));
1890 Local<v8::Object> instance1 = templ1->NewInstance();
1891 env->Global()->Set(v8_str("p"), instance1);
1892 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue());
1893 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue());
1894 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
1895 fun->PrototypeTemplate()->Set(isolate, "nirk", v8_num(123));
1896 Local<ObjectTemplate> templ2 = fun->InstanceTemplate();
1897 templ2->Set(isolate, "a", v8_num(12));
1898 templ2->Set(isolate, "b", templ1);
1899 Local<v8::Object> instance2 = templ2->NewInstance();
1900 env->Global()->Set(v8_str("q"), instance2);
1901 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue());
1902 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue());
1903 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue());
1904 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue());
1908 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) {
1909 ApiTestFuzzer::Fuzz();
1910 args.GetReturnValue().Set(v8_num(17.2));
1914 static void GetKnurd(Local<String> property,
1915 const v8::PropertyCallbackInfo<v8::Value>& info) {
1916 ApiTestFuzzer::Fuzz();
1917 info.GetReturnValue().Set(v8_num(15.2));
1921 THREADED_TEST(DescriptorInheritance) {
1922 v8::Isolate* isolate = CcTest::isolate();
1923 v8::HandleScope scope(isolate);
1924 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(isolate);
1925 super->PrototypeTemplate()->Set(isolate, "flabby",
1926 v8::FunctionTemplate::New(isolate,
1928 super->PrototypeTemplate()->Set(isolate, "PI", v8_num(3.14));
1930 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd);
1932 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(isolate);
1933 base1->Inherit(super);
1934 base1->PrototypeTemplate()->Set(isolate, "v1", v8_num(20.1));
1936 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(isolate);
1937 base2->Inherit(super);
1938 base2->PrototypeTemplate()->Set(isolate, "v2", v8_num(10.1));
1942 env->Global()->Set(v8_str("s"), super->GetFunction());
1943 env->Global()->Set(v8_str("base1"), base1->GetFunction());
1944 env->Global()->Set(v8_str("base2"), base2->GetFunction());
1946 // Checks right __proto__ chain.
1947 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue());
1948 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue());
1950 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue());
1952 // Instance accessor should not be visible on function object or its prototype
1953 CHECK(CompileRun("s.knurd == undefined")->BooleanValue());
1954 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue());
1955 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue());
1957 env->Global()->Set(v8_str("obj"),
1958 base1->GetFunction()->NewInstance());
1959 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue());
1960 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue());
1961 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue());
1962 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue());
1963 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue());
1965 env->Global()->Set(v8_str("obj2"),
1966 base2->GetFunction()->NewInstance());
1967 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue());
1968 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue());
1969 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue());
1970 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue());
1971 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue());
1973 // base1 and base2 cannot cross reference to each's prototype
1974 CHECK(v8_compile("obj.v2")->Run()->IsUndefined());
1975 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined());
1979 int echo_named_call_count;
1982 static void EchoNamedProperty(Local<String> name,
1983 const v8::PropertyCallbackInfo<v8::Value>& info) {
1984 ApiTestFuzzer::Fuzz();
1985 CHECK_EQ(v8_str("data"), info.Data());
1986 echo_named_call_count++;
1987 info.GetReturnValue().Set(name);
1991 // Helper functions for Interceptor/Accessor interaction tests
1993 void SimpleAccessorGetter(Local<String> name,
1994 const v8::PropertyCallbackInfo<v8::Value>& info) {
1995 Handle<Object> self = Handle<Object>::Cast(info.This());
1996 info.GetReturnValue().Set(
1997 self->Get(String::Concat(v8_str("accessor_"), name)));
2000 void SimpleAccessorSetter(Local<String> name, Local<Value> value,
2001 const v8::PropertyCallbackInfo<void>& info) {
2002 Handle<Object> self = Handle<Object>::Cast(info.This());
2003 self->Set(String::Concat(v8_str("accessor_"), name), value);
2006 void SymbolAccessorGetter(Local<Name> name,
2007 const v8::PropertyCallbackInfo<v8::Value>& info) {
2008 CHECK(name->IsSymbol());
2009 Local<Symbol> sym = Local<Symbol>::Cast(name);
2010 if (sym->Name()->IsUndefined())
2012 SimpleAccessorGetter(Local<String>::Cast(sym->Name()), info);
2015 void SymbolAccessorSetter(Local<Name> name, Local<Value> value,
2016 const v8::PropertyCallbackInfo<void>& info) {
2017 CHECK(name->IsSymbol());
2018 Local<Symbol> sym = Local<Symbol>::Cast(name);
2019 if (sym->Name()->IsUndefined())
2021 SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
2024 void SymbolAccessorGetterReturnsDefault(
2025 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2026 CHECK(name->IsSymbol());
2027 Local<Symbol> sym = Local<Symbol>::Cast(name);
2028 if (sym->Name()->IsUndefined()) return;
2029 info.GetReturnValue().Set(info.Data());
2032 static void ThrowingSymbolAccessorGetter(
2033 Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
2034 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
2037 void EmptyInterceptorGetter(Local<String> name,
2038 const v8::PropertyCallbackInfo<v8::Value>& info) {
2041 void EmptyInterceptorSetter(Local<String> name,
2043 const v8::PropertyCallbackInfo<v8::Value>& info) {
2046 void InterceptorGetter(Local<String> name,
2047 const v8::PropertyCallbackInfo<v8::Value>& info) {
2048 // Intercept names that start with 'interceptor_'.
2049 String::Utf8Value utf8(name);
2050 char* name_str = *utf8;
2051 char prefix[] = "interceptor_";
2053 for (i = 0; name_str[i] && prefix[i]; ++i) {
2054 if (name_str[i] != prefix[i]) return;
2056 Handle<Object> self = Handle<Object>::Cast(info.This());
2057 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
2060 void InterceptorSetter(Local<String> name,
2062 const v8::PropertyCallbackInfo<v8::Value>& info) {
2063 // Intercept accesses that set certain integer values, for which the name does
2064 // not start with 'accessor_'.
2065 String::Utf8Value utf8(name);
2066 char* name_str = *utf8;
2067 char prefix[] = "accessor_";
2069 for (i = 0; name_str[i] && prefix[i]; ++i) {
2070 if (name_str[i] != prefix[i]) break;
2072 if (!prefix[i]) return;
2074 if (value->IsInt32() && value->Int32Value() < 10000) {
2075 Handle<Object> self = Handle<Object>::Cast(info.This());
2076 self->SetHiddenValue(name, value);
2077 info.GetReturnValue().Set(value);
2081 void AddAccessor(Handle<FunctionTemplate> templ,
2082 Handle<String> name,
2083 v8::AccessorGetterCallback getter,
2084 v8::AccessorSetterCallback setter) {
2085 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2088 void AddInterceptor(Handle<FunctionTemplate> templ,
2089 v8::NamedPropertyGetterCallback getter,
2090 v8::NamedPropertySetterCallback setter) {
2091 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter);
2095 void AddAccessor(Handle<FunctionTemplate> templ,
2097 v8::AccessorNameGetterCallback getter,
2098 v8::AccessorNameSetterCallback setter) {
2099 templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
2103 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
2104 v8::HandleScope scope(CcTest::isolate());
2105 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2106 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2107 child->Inherit(parent);
2108 AddAccessor(parent, v8_str("age"),
2109 SimpleAccessorGetter, SimpleAccessorSetter);
2110 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2112 env->Global()->Set(v8_str("Child"), child->GetFunction());
2113 CompileRun("var child = new Child;"
2115 ExpectBoolean("child.hasOwnProperty('age')", false);
2116 ExpectInt32("child.age", 10);
2117 ExpectInt32("child.accessor_age", 10);
2121 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
2122 v8::Isolate* isolate = CcTest::isolate();
2123 v8::HandleScope scope(isolate);
2125 v8::Local<v8::Value> res = CompileRun("var a = []; a;");
2126 i::Handle<i::JSObject> a(v8::Utils::OpenHandle(v8::Object::Cast(*res)));
2127 CHECK(a->map()->instance_descriptors()->IsFixedArray());
2128 CHECK_GT(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2129 CompileRun("Object.defineProperty(a, 'length', { writable: false });");
2130 CHECK_EQ(i::FixedArray::cast(a->map()->instance_descriptors())->length(), 0);
2131 // But we should still have an ExecutableAccessorInfo.
2132 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
2133 i::LookupResult lookup(i_isolate);
2134 i::Handle<i::String> name(v8::Utils::OpenHandle(*v8_str("length")));
2135 i::LookupIterator it(a, name, i::LookupIterator::OWN_SKIP_INTERCEPTOR);
2136 CHECK_EQ(i::LookupIterator::ACCESSOR, it.state());
2137 CHECK(it.GetAccessors()->IsExecutableAccessorInfo());
2141 THREADED_TEST(EmptyInterceptorBreakTransitions) {
2142 v8::HandleScope scope(CcTest::isolate());
2143 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2144 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
2146 env->Global()->Set(v8_str("Constructor"), templ->GetFunction());
2147 CompileRun("var o1 = new Constructor;"
2148 "o1.a = 1;" // Ensure a and x share the descriptor array.
2149 "Object.defineProperty(o1, 'x', {value: 10});");
2150 CompileRun("var o2 = new Constructor;"
2152 "Object.defineProperty(o2, 'x', {value: 10});");
2156 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) {
2157 v8::Isolate* isolate = CcTest::isolate();
2158 v8::HandleScope scope(isolate);
2159 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2160 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2161 child->Inherit(parent);
2162 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2164 env->Global()->Set(v8_str("Child"), child->GetFunction());
2165 CompileRun("var child = new Child;"
2166 "var parent = child.__proto__;"
2167 "Object.defineProperty(parent, 'age', "
2168 " {get: function(){ return this.accessor_age; }, "
2169 " set: function(v){ this.accessor_age = v; }, "
2170 " enumerable: true, configurable: true});"
2172 ExpectBoolean("child.hasOwnProperty('age')", false);
2173 ExpectInt32("child.age", 10);
2174 ExpectInt32("child.accessor_age", 10);
2178 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) {
2179 v8::Isolate* isolate = CcTest::isolate();
2180 v8::HandleScope scope(isolate);
2181 Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
2182 Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
2183 child->Inherit(parent);
2184 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter);
2186 env->Global()->Set(v8_str("Child"), child->GetFunction());
2187 CompileRun("var child = new Child;"
2188 "var parent = child.__proto__;"
2189 "parent.name = 'Alice';");
2190 ExpectBoolean("child.hasOwnProperty('name')", false);
2191 ExpectString("child.name", "Alice");
2192 CompileRun("child.name = 'Bob';");
2193 ExpectString("child.name", "Bob");
2194 ExpectBoolean("child.hasOwnProperty('name')", true);
2195 ExpectString("parent.name", "Alice");
2199 THREADED_TEST(SwitchFromInterceptorToAccessor) {
2200 v8::HandleScope scope(CcTest::isolate());
2201 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2202 AddAccessor(templ, v8_str("age"),
2203 SimpleAccessorGetter, SimpleAccessorSetter);
2204 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2206 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2207 CompileRun("var obj = new Obj;"
2208 "function setAge(i){ obj.age = i; };"
2209 "for(var i = 0; i <= 10000; i++) setAge(i);");
2210 // All i < 10000 go to the interceptor.
2211 ExpectInt32("obj.interceptor_age", 9999);
2212 // The last i goes to the accessor.
2213 ExpectInt32("obj.accessor_age", 10000);
2217 THREADED_TEST(SwitchFromAccessorToInterceptor) {
2218 v8::HandleScope scope(CcTest::isolate());
2219 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2220 AddAccessor(templ, v8_str("age"),
2221 SimpleAccessorGetter, SimpleAccessorSetter);
2222 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2224 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2225 CompileRun("var obj = new Obj;"
2226 "function setAge(i){ obj.age = i; };"
2227 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2228 // All i >= 10000 go to the accessor.
2229 ExpectInt32("obj.accessor_age", 10000);
2230 // The last i goes to the interceptor.
2231 ExpectInt32("obj.interceptor_age", 9999);
2235 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) {
2236 v8::HandleScope scope(CcTest::isolate());
2237 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2238 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2239 child->Inherit(parent);
2240 AddAccessor(parent, v8_str("age"),
2241 SimpleAccessorGetter, SimpleAccessorSetter);
2242 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2244 env->Global()->Set(v8_str("Child"), child->GetFunction());
2245 CompileRun("var child = new Child;"
2246 "function setAge(i){ child.age = i; };"
2247 "for(var i = 0; i <= 10000; i++) setAge(i);");
2248 // All i < 10000 go to the interceptor.
2249 ExpectInt32("child.interceptor_age", 9999);
2250 // The last i goes to the accessor.
2251 ExpectInt32("child.accessor_age", 10000);
2255 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) {
2256 v8::HandleScope scope(CcTest::isolate());
2257 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2258 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2259 child->Inherit(parent);
2260 AddAccessor(parent, v8_str("age"),
2261 SimpleAccessorGetter, SimpleAccessorSetter);
2262 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2264 env->Global()->Set(v8_str("Child"), child->GetFunction());
2265 CompileRun("var child = new Child;"
2266 "function setAge(i){ child.age = i; };"
2267 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2268 // All i >= 10000 go to the accessor.
2269 ExpectInt32("child.accessor_age", 10000);
2270 // The last i goes to the interceptor.
2271 ExpectInt32("child.interceptor_age", 9999);
2275 THREADED_TEST(SwitchFromInterceptorToJSAccessor) {
2276 v8::HandleScope scope(CcTest::isolate());
2277 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2278 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2280 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2281 CompileRun("var obj = new Obj;"
2282 "function setter(i) { this.accessor_age = i; };"
2283 "function getter() { return this.accessor_age; };"
2284 "function setAge(i) { obj.age = i; };"
2285 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2286 "for(var i = 0; i <= 10000; i++) setAge(i);");
2287 // All i < 10000 go to the interceptor.
2288 ExpectInt32("obj.interceptor_age", 9999);
2289 // The last i goes to the JavaScript accessor.
2290 ExpectInt32("obj.accessor_age", 10000);
2291 // The installed JavaScript getter is still intact.
2292 // This last part is a regression test for issue 1651 and relies on the fact
2293 // that both interceptor and accessor are being installed on the same object.
2294 ExpectInt32("obj.age", 10000);
2295 ExpectBoolean("obj.hasOwnProperty('age')", true);
2296 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2300 THREADED_TEST(SwitchFromJSAccessorToInterceptor) {
2301 v8::HandleScope scope(CcTest::isolate());
2302 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
2303 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
2305 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
2306 CompileRun("var obj = new Obj;"
2307 "function setter(i) { this.accessor_age = i; };"
2308 "function getter() { return this.accessor_age; };"
2309 "function setAge(i) { obj.age = i; };"
2310 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
2311 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2312 // All i >= 10000 go to the accessor.
2313 ExpectInt32("obj.accessor_age", 10000);
2314 // The last i goes to the interceptor.
2315 ExpectInt32("obj.interceptor_age", 9999);
2316 // The installed JavaScript getter is still intact.
2317 // This last part is a regression test for issue 1651 and relies on the fact
2318 // that both interceptor and accessor are being installed on the same object.
2319 ExpectInt32("obj.age", 10000);
2320 ExpectBoolean("obj.hasOwnProperty('age')", true);
2321 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value");
2325 THREADED_TEST(SwitchFromInterceptorToProperty) {
2326 v8::HandleScope scope(CcTest::isolate());
2327 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2328 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2329 child->Inherit(parent);
2330 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2332 env->Global()->Set(v8_str("Child"), child->GetFunction());
2333 CompileRun("var child = new Child;"
2334 "function setAge(i){ child.age = i; };"
2335 "for(var i = 0; i <= 10000; i++) setAge(i);");
2336 // All i < 10000 go to the interceptor.
2337 ExpectInt32("child.interceptor_age", 9999);
2338 // The last i goes to child's own property.
2339 ExpectInt32("child.age", 10000);
2343 THREADED_TEST(SwitchFromPropertyToInterceptor) {
2344 v8::HandleScope scope(CcTest::isolate());
2345 Handle<FunctionTemplate> parent = FunctionTemplate::New(CcTest::isolate());
2346 Handle<FunctionTemplate> child = FunctionTemplate::New(CcTest::isolate());
2347 child->Inherit(parent);
2348 AddInterceptor(child, InterceptorGetter, InterceptorSetter);
2350 env->Global()->Set(v8_str("Child"), child->GetFunction());
2351 CompileRun("var child = new Child;"
2352 "function setAge(i){ child.age = i; };"
2353 "for(var i = 20000; i >= 9999; i--) setAge(i);");
2354 // All i >= 10000 go to child's own property.
2355 ExpectInt32("child.age", 10000);
2356 // The last i goes to the interceptor.
2357 ExpectInt32("child.interceptor_age", 9999);
2361 THREADED_TEST(NamedPropertyHandlerGetter) {
2362 echo_named_call_count = 0;
2363 v8::HandleScope scope(CcTest::isolate());
2364 v8::Handle<v8::FunctionTemplate> templ =
2365 v8::FunctionTemplate::New(CcTest::isolate());
2366 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
2370 env->Global()->Set(v8_str("obj"),
2371 templ->GetFunction()->NewInstance());
2372 CHECK_EQ(echo_named_call_count, 0);
2373 v8_compile("obj.x")->Run();
2374 CHECK_EQ(echo_named_call_count, 1);
2375 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;";
2376 v8::Handle<Value> str = CompileRun(code);
2377 String::Utf8Value value(str);
2378 CHECK_EQ(*value, "oddlepoddle");
2379 // Check default behavior
2380 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10);
2381 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue());
2382 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue());
2386 int echo_indexed_call_count = 0;
2389 static void EchoIndexedProperty(
2391 const v8::PropertyCallbackInfo<v8::Value>& info) {
2392 ApiTestFuzzer::Fuzz();
2393 CHECK_EQ(v8_num(637), info.Data());
2394 echo_indexed_call_count++;
2395 info.GetReturnValue().Set(v8_num(index));
2399 THREADED_TEST(IndexedPropertyHandlerGetter) {
2400 v8::Isolate* isolate = CcTest::isolate();
2401 v8::HandleScope scope(isolate);
2402 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2403 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
2407 env->Global()->Set(v8_str("obj"),
2408 templ->GetFunction()->NewInstance());
2409 Local<Script> script = v8_compile("obj[900]");
2410 CHECK_EQ(script->Run()->Int32Value(), 900);
2414 v8::Handle<v8::Object> bottom;
2416 static void CheckThisIndexedPropertyHandler(
2418 const v8::PropertyCallbackInfo<v8::Value>& info) {
2419 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
2420 ApiTestFuzzer::Fuzz();
2421 CHECK(info.This()->Equals(bottom));
2424 static void CheckThisNamedPropertyHandler(
2426 const v8::PropertyCallbackInfo<v8::Value>& info) {
2427 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
2428 ApiTestFuzzer::Fuzz();
2429 CHECK(info.This()->Equals(bottom));
2432 void CheckThisIndexedPropertySetter(
2435 const v8::PropertyCallbackInfo<v8::Value>& info) {
2436 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
2437 ApiTestFuzzer::Fuzz();
2438 CHECK(info.This()->Equals(bottom));
2442 void CheckThisNamedPropertySetter(
2443 Local<String> property,
2445 const v8::PropertyCallbackInfo<v8::Value>& info) {
2446 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
2447 ApiTestFuzzer::Fuzz();
2448 CHECK(info.This()->Equals(bottom));
2451 void CheckThisIndexedPropertyQuery(
2453 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2454 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
2455 ApiTestFuzzer::Fuzz();
2456 CHECK(info.This()->Equals(bottom));
2460 void CheckThisNamedPropertyQuery(
2461 Local<String> property,
2462 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2463 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
2464 ApiTestFuzzer::Fuzz();
2465 CHECK(info.This()->Equals(bottom));
2469 void CheckThisIndexedPropertyDeleter(
2471 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2472 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
2473 ApiTestFuzzer::Fuzz();
2474 CHECK(info.This()->Equals(bottom));
2478 void CheckThisNamedPropertyDeleter(
2479 Local<String> property,
2480 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
2481 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
2482 ApiTestFuzzer::Fuzz();
2483 CHECK(info.This()->Equals(bottom));
2487 void CheckThisIndexedPropertyEnumerator(
2488 const v8::PropertyCallbackInfo<v8::Array>& info) {
2489 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
2490 ApiTestFuzzer::Fuzz();
2491 CHECK(info.This()->Equals(bottom));
2495 void CheckThisNamedPropertyEnumerator(
2496 const v8::PropertyCallbackInfo<v8::Array>& info) {
2497 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
2498 ApiTestFuzzer::Fuzz();
2499 CHECK(info.This()->Equals(bottom));
2503 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) {
2505 v8::Isolate* isolate = env->GetIsolate();
2506 v8::HandleScope scope(isolate);
2508 // Set up a prototype chain with three interceptors.
2509 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2510 templ->InstanceTemplate()->SetIndexedPropertyHandler(
2511 CheckThisIndexedPropertyHandler,
2512 CheckThisIndexedPropertySetter,
2513 CheckThisIndexedPropertyQuery,
2514 CheckThisIndexedPropertyDeleter,
2515 CheckThisIndexedPropertyEnumerator);
2517 templ->InstanceTemplate()->SetNamedPropertyHandler(
2518 CheckThisNamedPropertyHandler,
2519 CheckThisNamedPropertySetter,
2520 CheckThisNamedPropertyQuery,
2521 CheckThisNamedPropertyDeleter,
2522 CheckThisNamedPropertyEnumerator);
2524 bottom = templ->GetFunction()->NewInstance();
2525 Local<v8::Object> top = templ->GetFunction()->NewInstance();
2526 Local<v8::Object> middle = templ->GetFunction()->NewInstance();
2528 bottom->SetPrototype(middle);
2529 middle->SetPrototype(top);
2530 env->Global()->Set(v8_str("obj"), bottom);
2532 // Indexed and named get.
2533 CompileRun("obj[0]");
2534 CompileRun("obj.x");
2536 // Indexed and named set.
2537 CompileRun("obj[1] = 42");
2538 CompileRun("obj.y = 42");
2540 // Indexed and named query.
2541 CompileRun("0 in obj");
2542 CompileRun("'x' in obj");
2544 // Indexed and named deleter.
2545 CompileRun("delete obj[0]");
2546 CompileRun("delete obj.x");
2549 CompileRun("for (var p in obj) ;");
2553 static void PrePropertyHandlerGet(
2555 const v8::PropertyCallbackInfo<v8::Value>& info) {
2556 ApiTestFuzzer::Fuzz();
2557 if (v8_str("pre")->Equals(key)) {
2558 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
2563 static void PrePropertyHandlerQuery(
2565 const v8::PropertyCallbackInfo<v8::Integer>& info) {
2566 if (v8_str("pre")->Equals(key)) {
2567 info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
2572 THREADED_TEST(PrePropertyHandler) {
2573 v8::Isolate* isolate = CcTest::isolate();
2574 v8::HandleScope scope(isolate);
2575 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
2576 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
2578 PrePropertyHandlerQuery);
2579 LocalContext env(NULL, desc->InstanceTemplate());
2580 CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
2581 v8::Handle<Value> result_pre = CompileRun("pre");
2582 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre);
2583 v8::Handle<Value> result_on = CompileRun("on");
2584 CHECK_EQ(v8_str("Object: on"), result_on);
2585 v8::Handle<Value> result_post = CompileRun("post");
2586 CHECK(result_post.IsEmpty());
2590 THREADED_TEST(UndefinedIsNotEnumerable) {
2592 v8::HandleScope scope(env->GetIsolate());
2593 v8::Handle<Value> result = CompileRun("this.propertyIsEnumerable(undefined)");
2594 CHECK(result->IsFalse());
2598 v8::Handle<Script> call_recursively_script;
2599 static const int kTargetRecursionDepth = 200; // near maximum
2602 static void CallScriptRecursivelyCall(
2603 const v8::FunctionCallbackInfo<v8::Value>& args) {
2604 ApiTestFuzzer::Fuzz();
2605 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2606 if (depth == kTargetRecursionDepth) return;
2607 args.This()->Set(v8_str("depth"),
2608 v8::Integer::New(args.GetIsolate(), depth + 1));
2609 args.GetReturnValue().Set(call_recursively_script->Run());
2613 static void CallFunctionRecursivelyCall(
2614 const v8::FunctionCallbackInfo<v8::Value>& args) {
2615 ApiTestFuzzer::Fuzz();
2616 int depth = args.This()->Get(v8_str("depth"))->Int32Value();
2617 if (depth == kTargetRecursionDepth) {
2618 printf("[depth = %d]\n", depth);
2621 args.This()->Set(v8_str("depth"),
2622 v8::Integer::New(args.GetIsolate(), depth + 1));
2623 v8::Handle<Value> function =
2624 args.This()->Get(v8_str("callFunctionRecursively"));
2625 args.GetReturnValue().Set(
2626 function.As<Function>()->Call(args.This(), 0, NULL));
2630 THREADED_TEST(DeepCrossLanguageRecursion) {
2631 v8::Isolate* isolate = CcTest::isolate();
2632 v8::HandleScope scope(isolate);
2633 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
2634 global->Set(v8_str("callScriptRecursively"),
2635 v8::FunctionTemplate::New(isolate, CallScriptRecursivelyCall));
2636 global->Set(v8_str("callFunctionRecursively"),
2637 v8::FunctionTemplate::New(isolate, CallFunctionRecursivelyCall));
2638 LocalContext env(NULL, global);
2640 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2641 call_recursively_script = v8_compile("callScriptRecursively()");
2642 call_recursively_script->Run();
2643 call_recursively_script = v8::Handle<Script>();
2645 env->Global()->Set(v8_str("depth"), v8::Integer::New(isolate, 0));
2646 CompileRun("callFunctionRecursively()");
2650 static void ThrowingPropertyHandlerGet(
2652 const v8::PropertyCallbackInfo<v8::Value>& info) {
2653 ApiTestFuzzer::Fuzz();
2654 info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
2658 static void ThrowingPropertyHandlerSet(
2661 const v8::PropertyCallbackInfo<v8::Value>& info) {
2662 info.GetIsolate()->ThrowException(key);
2663 info.GetReturnValue().SetUndefined(); // not the same as empty handle
2667 THREADED_TEST(CallbackExceptionRegression) {
2668 v8::Isolate* isolate = CcTest::isolate();
2669 v8::HandleScope scope(isolate);
2670 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
2671 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
2672 ThrowingPropertyHandlerSet);
2674 env->Global()->Set(v8_str("obj"), obj->NewInstance());
2675 v8::Handle<Value> otto = CompileRun(
2676 "try { with (obj) { otto; } } catch (e) { e; }");
2677 CHECK_EQ(v8_str("otto"), otto);
2678 v8::Handle<Value> netto = CompileRun(
2679 "try { with (obj) { netto = 4; } } catch (e) { e; }");
2680 CHECK_EQ(v8_str("netto"), netto);
2684 THREADED_TEST(FunctionPrototype) {
2685 v8::Isolate* isolate = CcTest::isolate();
2686 v8::HandleScope scope(isolate);
2687 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(isolate);
2688 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321));
2690 env->Global()->Set(v8_str("Foo"), Foo->GetFunction());
2691 Local<Script> script = v8_compile("Foo.prototype.plak");
2692 CHECK_EQ(script->Run()->Int32Value(), 321);
2696 THREADED_TEST(InternalFields) {
2698 v8::Isolate* isolate = env->GetIsolate();
2699 v8::HandleScope scope(isolate);
2701 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2702 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2703 instance_templ->SetInternalFieldCount(1);
2704 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2705 CHECK_EQ(1, obj->InternalFieldCount());
2706 CHECK(obj->GetInternalField(0)->IsUndefined());
2707 obj->SetInternalField(0, v8_num(17));
2708 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value());
2712 THREADED_TEST(GlobalObjectInternalFields) {
2713 v8::Isolate* isolate = CcTest::isolate();
2714 v8::HandleScope scope(isolate);
2715 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
2716 global_template->SetInternalFieldCount(1);
2717 LocalContext env(NULL, global_template);
2718 v8::Handle<v8::Object> global_proxy = env->Global();
2719 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>();
2720 CHECK_EQ(1, global->InternalFieldCount());
2721 CHECK(global->GetInternalField(0)->IsUndefined());
2722 global->SetInternalField(0, v8_num(17));
2723 CHECK_EQ(17, global->GetInternalField(0)->Int32Value());
2727 THREADED_TEST(GlobalObjectHasRealIndexedProperty) {
2729 v8::HandleScope scope(CcTest::isolate());
2731 v8::Local<v8::Object> global = env->Global();
2732 global->Set(0, v8::String::NewFromUtf8(CcTest::isolate(), "value"));
2733 CHECK(global->HasRealIndexedProperty(0));
2737 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj,
2739 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2740 obj->SetAlignedPointerInInternalField(0, value);
2741 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2742 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0));
2746 THREADED_TEST(InternalFieldsAlignedPointers) {
2748 v8::Isolate* isolate = env->GetIsolate();
2749 v8::HandleScope scope(isolate);
2751 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
2752 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
2753 instance_templ->SetInternalFieldCount(1);
2754 Local<v8::Object> obj = templ->GetFunction()->NewInstance();
2755 CHECK_EQ(1, obj->InternalFieldCount());
2757 CheckAlignedPointerInInternalField(obj, NULL);
2759 int* heap_allocated = new int[100];
2760 CheckAlignedPointerInInternalField(obj, heap_allocated);
2761 delete[] heap_allocated;
2763 int stack_allocated[100];
2764 CheckAlignedPointerInInternalField(obj, stack_allocated);
2766 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2767 CheckAlignedPointerInInternalField(obj, huge);
2769 v8::UniquePersistent<v8::Object> persistent(isolate, obj);
2770 CHECK_EQ(1, Object::InternalFieldCount(persistent));
2771 CHECK_EQ(huge, Object::GetAlignedPointerFromInternalField(persistent, 0));
2775 static void CheckAlignedPointerInEmbedderData(LocalContext* env,
2778 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1));
2779 (*env)->SetAlignedPointerInEmbedderData(index, value);
2780 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2781 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index));
2785 static void* AlignedTestPointer(int i) {
2786 return reinterpret_cast<void*>(i * 1234);
2790 THREADED_TEST(EmbedderDataAlignedPointers) {
2792 v8::HandleScope scope(env->GetIsolate());
2794 CheckAlignedPointerInEmbedderData(&env, 0, NULL);
2796 int* heap_allocated = new int[100];
2797 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated);
2798 delete[] heap_allocated;
2800 int stack_allocated[100];
2801 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated);
2803 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1));
2804 CheckAlignedPointerInEmbedderData(&env, 3, huge);
2806 // Test growing of the embedder data's backing store.
2807 for (int i = 0; i < 100; i++) {
2808 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i));
2810 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2811 for (int i = 0; i < 100; i++) {
2812 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i));
2817 static void CheckEmbedderData(LocalContext* env,
2819 v8::Handle<Value> data) {
2820 (*env)->SetEmbedderData(index, data);
2821 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data));
2825 THREADED_TEST(EmbedderData) {
2827 v8::Isolate* isolate = env->GetIsolate();
2828 v8::HandleScope scope(isolate);
2832 v8::String::NewFromUtf8(isolate, "The quick brown fox jumps"));
2833 CheckEmbedderData(&env, 2, v8::String::NewFromUtf8(isolate,
2834 "over the lazy dog."));
2835 CheckEmbedderData(&env, 1, v8::Number::New(isolate, 1.2345));
2836 CheckEmbedderData(&env, 0, v8::Boolean::New(isolate, true));
2840 THREADED_TEST(GetIsolate) {
2842 v8::Isolate* isolate = env->GetIsolate();
2843 v8::HandleScope scope(isolate);
2844 Local<v8::Object> obj = v8::Object::New(isolate);
2845 CHECK_EQ(isolate, obj->GetIsolate());
2846 CHECK_EQ(isolate, CcTest::global()->GetIsolate());
2850 THREADED_TEST(IdentityHash) {
2852 v8::Isolate* isolate = env->GetIsolate();
2853 v8::HandleScope scope(isolate);
2855 // Ensure that the test starts with an fresh heap to test whether the hash
2856 // code is based on the address.
2857 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2858 Local<v8::Object> obj = v8::Object::New(isolate);
2859 int hash = obj->GetIdentityHash();
2860 int hash1 = obj->GetIdentityHash();
2861 CHECK_EQ(hash, hash1);
2862 int hash2 = v8::Object::New(isolate)->GetIdentityHash();
2863 // Since the identity hash is essentially a random number two consecutive
2864 // objects should not be assigned the same hash code. If the test below fails
2865 // the random number generator should be evaluated.
2866 CHECK_NE(hash, hash2);
2867 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2868 int hash3 = v8::Object::New(isolate)->GetIdentityHash();
2869 // Make sure that the identity hash is not based on the initial address of
2870 // the object alone. If the test below fails the random number generator
2871 // should be evaluated.
2872 CHECK_NE(hash, hash3);
2873 int hash4 = obj->GetIdentityHash();
2874 CHECK_EQ(hash, hash4);
2876 // Check identity hashes behaviour in the presence of JS accessors.
2877 // Put a getter for 'v8::IdentityHash' on the Object's prototype:
2879 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n");
2880 Local<v8::Object> o1 = v8::Object::New(isolate);
2881 Local<v8::Object> o2 = v8::Object::New(isolate);
2882 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2886 "function cnst() { return 42; };\n"
2887 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n");
2888 Local<v8::Object> o1 = v8::Object::New(isolate);
2889 Local<v8::Object> o2 = v8::Object::New(isolate);
2890 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash());
2895 THREADED_TEST(GlobalProxyIdentityHash) {
2897 v8::Isolate* isolate = env->GetIsolate();
2898 v8::HandleScope scope(isolate);
2899 Handle<Object> global_proxy = env->Global();
2900 int hash1 = global_proxy->GetIdentityHash();
2901 // Hash should be retained after being detached.
2902 env->DetachGlobal();
2903 int hash2 = global_proxy->GetIdentityHash();
2904 CHECK_EQ(hash1, hash2);
2906 // Re-attach global proxy to a new context, hash should stay the same.
2907 LocalContext env2(NULL, Handle<ObjectTemplate>(), global_proxy);
2908 int hash3 = global_proxy->GetIdentityHash();
2909 CHECK_EQ(hash1, hash3);
2914 THREADED_TEST(SymbolProperties) {
2916 v8::Isolate* isolate = env->GetIsolate();
2917 v8::HandleScope scope(isolate);
2919 v8::Local<v8::Object> obj = v8::Object::New(isolate);
2920 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate);
2921 v8::Local<v8::Symbol> sym2 =
2922 v8::Symbol::New(isolate, v8_str("my-symbol"));
2923 v8::Local<v8::Symbol> sym3 =
2924 v8::Symbol::New(isolate, v8_str("sym3"));
2926 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2928 // Check basic symbol functionality.
2929 CHECK(sym1->IsSymbol());
2930 CHECK(sym2->IsSymbol());
2931 CHECK(!obj->IsSymbol());
2933 CHECK(sym1->Equals(sym1));
2934 CHECK(sym2->Equals(sym2));
2935 CHECK(!sym1->Equals(sym2));
2936 CHECK(!sym2->Equals(sym1));
2937 CHECK(sym1->StrictEquals(sym1));
2938 CHECK(sym2->StrictEquals(sym2));
2939 CHECK(!sym1->StrictEquals(sym2));
2940 CHECK(!sym2->StrictEquals(sym1));
2942 CHECK(sym2->Name()->Equals(v8_str("my-symbol")));
2944 v8::Local<v8::Value> sym_val = sym2;
2945 CHECK(sym_val->IsSymbol());
2946 CHECK(sym_val->Equals(sym2));
2947 CHECK(sym_val->StrictEquals(sym2));
2948 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2));
2950 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2);
2951 CHECK(sym_obj->IsSymbolObject());
2952 CHECK(!sym2->IsSymbolObject());
2953 CHECK(!obj->IsSymbolObject());
2954 CHECK(!sym_obj->Equals(sym2));
2955 CHECK(!sym_obj->StrictEquals(sym2));
2956 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj));
2957 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2));
2959 // Make sure delete of a non-existent symbol property works.
2960 CHECK(obj->Delete(sym1));
2961 CHECK(!obj->Has(sym1));
2963 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 1503)));
2964 CHECK(obj->Has(sym1));
2965 CHECK_EQ(1503, obj->Get(sym1)->Int32Value());
2966 CHECK(obj->Set(sym1, v8::Integer::New(isolate, 2002)));
2967 CHECK(obj->Has(sym1));
2968 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2969 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1));
2971 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
2972 int num_props = obj->GetPropertyNames()->Length();
2973 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
2974 v8::Integer::New(isolate, 20)));
2975 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
2976 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
2978 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
2980 CHECK(obj->SetAccessor(sym3, SymbolAccessorGetter, SymbolAccessorSetter));
2981 CHECK(obj->Get(sym3)->IsUndefined());
2982 CHECK(obj->Set(sym3, v8::Integer::New(isolate, 42)));
2983 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
2984 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
2985 v8::Integer::New(isolate, 42)));
2987 // Add another property and delete it afterwards to force the object in
2989 CHECK(obj->Set(sym2, v8::Integer::New(isolate, 2008)));
2990 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2991 CHECK_EQ(2008, obj->Get(sym2)->Int32Value());
2992 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
2993 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
2995 CHECK(obj->Has(sym1));
2996 CHECK(obj->Has(sym2));
2997 CHECK(obj->Has(sym3));
2998 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
2999 CHECK(obj->Delete(sym2));
3000 CHECK(obj->Has(sym1));
3001 CHECK(!obj->Has(sym2));
3002 CHECK(obj->Has(sym3));
3003 CHECK(obj->Has(v8::String::NewFromUtf8(isolate, "accessor_sym3")));
3004 CHECK_EQ(2002, obj->Get(sym1)->Int32Value());
3005 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3006 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3007 v8::Integer::New(isolate, 42)));
3008 CHECK_EQ(2, obj->GetOwnPropertyNames()->Length());
3010 // Symbol properties are inherited.
3011 v8::Local<v8::Object> child = v8::Object::New(isolate);
3012 child->SetPrototype(obj);
3013 CHECK(child->Has(sym1));
3014 CHECK_EQ(2002, child->Get(sym1)->Int32Value());
3015 CHECK(obj->Get(sym3)->Equals(v8::Integer::New(isolate, 42)));
3016 CHECK(obj->Get(v8::String::NewFromUtf8(isolate, "accessor_sym3"))->Equals(
3017 v8::Integer::New(isolate, 42)));
3018 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3022 THREADED_TEST(SymbolTemplateProperties) {
3024 v8::Isolate* isolate = env->GetIsolate();
3025 v8::HandleScope scope(isolate);
3026 v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
3027 v8::Local<v8::Name> name = v8::Symbol::New(isolate);
3028 CHECK(!name.IsEmpty());
3029 foo->PrototypeTemplate()->Set(name, v8::FunctionTemplate::New(isolate));
3030 v8::Local<v8::Object> new_instance = foo->InstanceTemplate()->NewInstance();
3031 CHECK(!new_instance.IsEmpty());
3032 CHECK(new_instance->Has(name));
3036 THREADED_TEST(PrivateProperties) {
3038 v8::Isolate* isolate = env->GetIsolate();
3039 v8::HandleScope scope(isolate);
3041 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3042 v8::Local<v8::Private> priv1 = v8::Private::New(isolate);
3043 v8::Local<v8::Private> priv2 =
3044 v8::Private::New(isolate, v8_str("my-private"));
3046 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3048 CHECK(priv2->Name()->Equals(v8::String::NewFromUtf8(isolate, "my-private")));
3050 // Make sure delete of a non-existent private symbol property works.
3051 CHECK(obj->DeletePrivate(priv1));
3052 CHECK(!obj->HasPrivate(priv1));
3054 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 1503)));
3055 CHECK(obj->HasPrivate(priv1));
3056 CHECK_EQ(1503, obj->GetPrivate(priv1)->Int32Value());
3057 CHECK(obj->SetPrivate(priv1, v8::Integer::New(isolate, 2002)));
3058 CHECK(obj->HasPrivate(priv1));
3059 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3061 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length());
3062 int num_props = obj->GetPropertyNames()->Length();
3063 CHECK(obj->Set(v8::String::NewFromUtf8(isolate, "bla"),
3064 v8::Integer::New(isolate, 20)));
3065 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3066 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length());
3068 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3070 // Add another property and delete it afterwards to force the object in
3072 CHECK(obj->SetPrivate(priv2, v8::Integer::New(isolate, 2008)));
3073 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3074 CHECK_EQ(2008, obj->GetPrivate(priv2)->Int32Value());
3075 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3076 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3078 CHECK(obj->HasPrivate(priv1));
3079 CHECK(obj->HasPrivate(priv2));
3080 CHECK(obj->DeletePrivate(priv2));
3081 CHECK(obj->HasPrivate(priv1));
3082 CHECK(!obj->HasPrivate(priv2));
3083 CHECK_EQ(2002, obj->GetPrivate(priv1)->Int32Value());
3084 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length());
3086 // Private properties are inherited (for the time being).
3087 v8::Local<v8::Object> child = v8::Object::New(isolate);
3088 child->SetPrototype(obj);
3089 CHECK(child->HasPrivate(priv1));
3090 CHECK_EQ(2002, child->GetPrivate(priv1)->Int32Value());
3091 CHECK_EQ(0, child->GetOwnPropertyNames()->Length());
3095 THREADED_TEST(GlobalSymbols) {
3097 v8::Isolate* isolate = env->GetIsolate();
3098 v8::HandleScope scope(isolate);
3100 v8::Local<String> name = v8_str("my-symbol");
3101 v8::Local<v8::Symbol> glob = v8::Symbol::For(isolate, name);
3102 v8::Local<v8::Symbol> glob2 = v8::Symbol::For(isolate, name);
3103 CHECK(glob2->SameValue(glob));
3105 v8::Local<v8::Symbol> glob_api = v8::Symbol::ForApi(isolate, name);
3106 v8::Local<v8::Symbol> glob_api2 = v8::Symbol::ForApi(isolate, name);
3107 CHECK(glob_api2->SameValue(glob_api));
3108 CHECK(!glob_api->SameValue(glob));
3110 v8::Local<v8::Symbol> sym = v8::Symbol::New(isolate, name);
3111 CHECK(!sym->SameValue(glob));
3113 CompileRun("var sym2 = Symbol.for('my-symbol')");
3114 v8::Local<Value> sym2 = env->Global()->Get(v8_str("sym2"));
3115 CHECK(sym2->SameValue(glob));
3116 CHECK(!sym2->SameValue(glob_api));
3120 static void CheckWellKnownSymbol(v8::Local<v8::Symbol>(*getter)(v8::Isolate*),
3123 v8::Isolate* isolate = env->GetIsolate();
3124 v8::HandleScope scope(isolate);
3126 v8::Local<v8::Symbol> symbol = getter(isolate);
3127 std::string script = std::string("var sym = ") + name;
3128 CompileRun(script.c_str());
3129 v8::Local<Value> value = env->Global()->Get(v8_str("sym"));
3131 CHECK(!value.IsEmpty());
3132 CHECK(!symbol.IsEmpty());
3133 CHECK(value->SameValue(symbol));
3137 THREADED_TEST(WellKnownSymbols) {
3138 CheckWellKnownSymbol(v8::Symbol::GetIterator, "Symbol.iterator");
3139 CheckWellKnownSymbol(v8::Symbol::GetUnscopables, "Symbol.unscopables");
3143 THREADED_TEST(GlobalPrivates) {
3145 v8::Isolate* isolate = env->GetIsolate();
3146 v8::HandleScope scope(isolate);
3148 v8::Local<String> name = v8_str("my-private");
3149 v8::Local<v8::Private> glob = v8::Private::ForApi(isolate, name);
3150 v8::Local<v8::Object> obj = v8::Object::New(isolate);
3151 CHECK(obj->SetPrivate(glob, v8::Integer::New(isolate, 3)));
3153 v8::Local<v8::Private> glob2 = v8::Private::ForApi(isolate, name);
3154 CHECK(obj->HasPrivate(glob2));
3156 v8::Local<v8::Private> priv = v8::Private::New(isolate, name);
3157 CHECK(!obj->HasPrivate(priv));
3159 CompileRun("var intern = %CreateGlobalPrivateSymbol('my-private')");
3160 v8::Local<Value> intern = env->Global()->Get(v8_str("intern"));
3161 CHECK(!obj->Has(intern));
3165 class ScopedArrayBufferContents {
3167 explicit ScopedArrayBufferContents(
3168 const v8::ArrayBuffer::Contents& contents)
3169 : contents_(contents) {}
3170 ~ScopedArrayBufferContents() { free(contents_.Data()); }
3171 void* Data() const { return contents_.Data(); }
3172 size_t ByteLength() const { return contents_.ByteLength(); }
3174 const v8::ArrayBuffer::Contents contents_;
3177 template <typename T>
3178 static void CheckInternalFieldsAreZero(v8::Handle<T> value) {
3179 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount());
3180 for (int i = 0; i < value->InternalFieldCount(); i++) {
3181 CHECK_EQ(0, value->GetInternalField(i)->Int32Value());
3186 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) {
3188 v8::Isolate* isolate = env->GetIsolate();
3189 v8::HandleScope handle_scope(isolate);
3191 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(isolate, 1024);
3192 CheckInternalFieldsAreZero(ab);
3193 CHECK_EQ(1024, static_cast<int>(ab->ByteLength()));
3194 CHECK(!ab->IsExternal());
3195 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3197 ScopedArrayBufferContents ab_contents(ab->Externalize());
3198 CHECK(ab->IsExternal());
3200 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength()));
3201 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data());
3202 DCHECK(data != NULL);
3203 env->Global()->Set(v8_str("ab"), ab);
3205 v8::Handle<v8::Value> result = CompileRun("ab.byteLength");
3206 CHECK_EQ(1024, result->Int32Value());
3208 result = CompileRun("var u8 = new Uint8Array(ab);"
3212 CHECK_EQ(1024, result->Int32Value());
3213 CHECK_EQ(0xFF, data[0]);
3214 CHECK_EQ(0xAA, data[1]);
3217 result = CompileRun("u8[0] + u8[1]");
3218 CHECK_EQ(0xDD, result->Int32Value());
3222 THREADED_TEST(ArrayBuffer_JSInternalToExternal) {
3224 v8::Isolate* isolate = env->GetIsolate();
3225 v8::HandleScope handle_scope(isolate);
3228 v8::Local<v8::Value> result =
3229 CompileRun("var ab1 = new ArrayBuffer(2);"
3230 "var u8_a = new Uint8Array(ab1);"
3232 "u8_a[1] = 0xFF; u8_a.buffer");
3233 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result);
3234 CheckInternalFieldsAreZero(ab1);
3235 CHECK_EQ(2, static_cast<int>(ab1->ByteLength()));
3236 CHECK(!ab1->IsExternal());
3237 ScopedArrayBufferContents ab1_contents(ab1->Externalize());
3238 CHECK(ab1->IsExternal());
3240 result = CompileRun("ab1.byteLength");
3241 CHECK_EQ(2, result->Int32Value());
3242 result = CompileRun("u8_a[0]");
3243 CHECK_EQ(0xAA, result->Int32Value());
3244 result = CompileRun("u8_a[1]");
3245 CHECK_EQ(0xFF, result->Int32Value());
3246 result = CompileRun("var u8_b = new Uint8Array(ab1);"
3249 CHECK_EQ(0xBB, result->Int32Value());
3250 result = CompileRun("u8_b[1]");
3251 CHECK_EQ(0xFF, result->Int32Value());
3253 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength()));
3254 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data());
3255 CHECK_EQ(0xBB, ab1_data[0]);
3256 CHECK_EQ(0xFF, ab1_data[1]);
3259 result = CompileRun("u8_a[0] + u8_a[1]");
3260 CHECK_EQ(0xDD, result->Int32Value());
3264 THREADED_TEST(ArrayBuffer_External) {
3266 v8::Isolate* isolate = env->GetIsolate();
3267 v8::HandleScope handle_scope(isolate);
3269 i::ScopedVector<uint8_t> my_data(100);
3270 memset(my_data.start(), 0, 100);
3271 Local<v8::ArrayBuffer> ab3 =
3272 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3273 CheckInternalFieldsAreZero(ab3);
3274 CHECK_EQ(100, static_cast<int>(ab3->ByteLength()));
3275 CHECK(ab3->IsExternal());
3277 env->Global()->Set(v8_str("ab3"), ab3);
3279 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength");
3280 CHECK_EQ(100, result->Int32Value());
3282 result = CompileRun("var u8_b = new Uint8Array(ab3);"
3286 CHECK_EQ(100, result->Int32Value());
3287 CHECK_EQ(0xBB, my_data[0]);
3288 CHECK_EQ(0xCC, my_data[1]);
3291 result = CompileRun("u8_b[0] + u8_b[1]");
3292 CHECK_EQ(0xDD, result->Int32Value());
3296 THREADED_TEST(ArrayBuffer_DisableNeuter) {
3298 v8::Isolate* isolate = env->GetIsolate();
3299 v8::HandleScope handle_scope(isolate);
3301 i::ScopedVector<uint8_t> my_data(100);
3302 memset(my_data.start(), 0, 100);
3303 Local<v8::ArrayBuffer> ab =
3304 v8::ArrayBuffer::New(isolate, my_data.start(), 100);
3305 CHECK(ab->IsNeuterable());
3307 i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
3308 buf->set_is_neuterable(false);
3310 CHECK(!ab->IsNeuterable());
3314 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
3315 CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
3316 CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
3320 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) {
3321 CHECK_EQ(0, static_cast<int>(ta->ByteLength()));
3322 CHECK_EQ(0, static_cast<int>(ta->Length()));
3323 CHECK_EQ(0, static_cast<int>(ta->ByteOffset()));
3327 static void CheckIsTypedArrayVarNeutered(const char* name) {
3328 i::ScopedVector<char> source(1024);
3330 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0",
3332 CHECK(CompileRun(source.start())->IsTrue());
3333 v8::Handle<v8::TypedArray> ta =
3334 v8::Handle<v8::TypedArray>::Cast(CompileRun(name));
3335 CheckIsNeutered(ta);
3339 template <typename TypedArray, int kElementSize>
3340 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab,
3343 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length);
3344 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
3345 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset()));
3346 CHECK_EQ(length, static_cast<int>(ta->Length()));
3347 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength()));
3352 THREADED_TEST(ArrayBuffer_NeuteringApi) {
3354 v8::Isolate* isolate = env->GetIsolate();
3355 v8::HandleScope handle_scope(isolate);
3357 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(isolate, 1024);
3359 v8::Handle<v8::Uint8Array> u8a =
3360 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023);
3361 v8::Handle<v8::Uint8ClampedArray> u8c =
3362 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023);
3363 v8::Handle<v8::Int8Array> i8a =
3364 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023);
3366 v8::Handle<v8::Uint16Array> u16a =
3367 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511);
3368 v8::Handle<v8::Int16Array> i16a =
3369 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511);
3371 v8::Handle<v8::Uint32Array> u32a =
3372 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255);
3373 v8::Handle<v8::Int32Array> i32a =
3374 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255);
3376 v8::Handle<v8::Float32Array> f32a =
3377 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255);
3378 v8::Handle<v8::Float64Array> f64a =
3379 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127);
3381 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023);
3382 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
3383 CHECK_EQ(1, static_cast<int>(dv->ByteOffset()));
3384 CHECK_EQ(1023, static_cast<int>(dv->ByteLength()));
3386 ScopedArrayBufferContents contents(buffer->Externalize());
3388 CHECK_EQ(0, static_cast<int>(buffer->ByteLength()));
3389 CheckIsNeutered(u8a);
3390 CheckIsNeutered(u8c);
3391 CheckIsNeutered(i8a);
3392 CheckIsNeutered(u16a);
3393 CheckIsNeutered(i16a);
3394 CheckIsNeutered(u32a);
3395 CheckIsNeutered(i32a);
3396 CheckIsNeutered(f32a);
3397 CheckIsNeutered(f64a);
3398 CheckDataViewIsNeutered(dv);
3402 THREADED_TEST(ArrayBuffer_NeuteringScript) {
3404 v8::Isolate* isolate = env->GetIsolate();
3405 v8::HandleScope handle_scope(isolate);
3408 "var ab = new ArrayBuffer(1024);"
3409 "var u8a = new Uint8Array(ab, 1, 1023);"
3410 "var u8c = new Uint8ClampedArray(ab, 1, 1023);"
3411 "var i8a = new Int8Array(ab, 1, 1023);"
3412 "var u16a = new Uint16Array(ab, 2, 511);"
3413 "var i16a = new Int16Array(ab, 2, 511);"
3414 "var u32a = new Uint32Array(ab, 4, 255);"
3415 "var i32a = new Int32Array(ab, 4, 255);"
3416 "var f32a = new Float32Array(ab, 4, 255);"
3417 "var f64a = new Float64Array(ab, 8, 127);"
3418 "var dv = new DataView(ab, 1, 1023);");
3420 v8::Handle<v8::ArrayBuffer> ab =
3421 Local<v8::ArrayBuffer>::Cast(CompileRun("ab"));
3423 v8::Handle<v8::DataView> dv =
3424 v8::Handle<v8::DataView>::Cast(CompileRun("dv"));
3426 ScopedArrayBufferContents contents(ab->Externalize());
3428 CHECK_EQ(0, static_cast<int>(ab->ByteLength()));
3429 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value());
3431 CheckIsTypedArrayVarNeutered("u8a");
3432 CheckIsTypedArrayVarNeutered("u8c");
3433 CheckIsTypedArrayVarNeutered("i8a");
3434 CheckIsTypedArrayVarNeutered("u16a");
3435 CheckIsTypedArrayVarNeutered("i16a");
3436 CheckIsTypedArrayVarNeutered("u32a");
3437 CheckIsTypedArrayVarNeutered("i32a");
3438 CheckIsTypedArrayVarNeutered("f32a");
3439 CheckIsTypedArrayVarNeutered("f64a");
3441 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue());
3442 CheckDataViewIsNeutered(dv);
3447 THREADED_TEST(HiddenProperties) {
3449 v8::Isolate* isolate = env->GetIsolate();
3450 v8::HandleScope scope(isolate);
3452 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3453 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3454 v8::Local<v8::String> empty = v8_str("");
3455 v8::Local<v8::String> prop_name = v8_str("prop_name");
3457 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3459 // Make sure delete of a non-existent hidden value works
3460 CHECK(obj->DeleteHiddenValue(key));
3462 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 1503)));
3463 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value());
3464 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3465 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3467 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3469 // Make sure we do not find the hidden property.
3470 CHECK(!obj->Has(empty));
3471 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3472 CHECK(obj->Get(empty)->IsUndefined());
3473 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3474 CHECK(obj->Set(empty, v8::Integer::New(isolate, 2003)));
3475 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3476 CHECK_EQ(2003, obj->Get(empty)->Int32Value());
3478 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3480 // Add another property and delete it afterwards to force the object in
3482 CHECK(obj->Set(prop_name, v8::Integer::New(isolate, 2008)));
3483 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3484 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value());
3485 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3486 CHECK(obj->Delete(prop_name));
3487 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value());
3489 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
3491 CHECK(obj->SetHiddenValue(key, Handle<Value>()));
3492 CHECK(obj->GetHiddenValue(key).IsEmpty());
3494 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2002)));
3495 CHECK(obj->DeleteHiddenValue(key));
3496 CHECK(obj->GetHiddenValue(key).IsEmpty());
3500 THREADED_TEST(Regress97784) {
3501 // Regression test for crbug.com/97784
3502 // Messing with the Object.prototype should not have effect on
3503 // hidden properties.
3505 v8::HandleScope scope(env->GetIsolate());
3507 v8::Local<v8::Object> obj = v8::Object::New(env->GetIsolate());
3508 v8::Local<v8::String> key = v8_str("hidden");
3511 "set_called = false;"
3512 "Object.defineProperty("
3513 " Object.prototype,"
3515 " {get: function() { return 45; },"
3516 " set: function() { set_called = true; }})");
3518 CHECK(obj->GetHiddenValue(key).IsEmpty());
3519 // Make sure that the getter and setter from Object.prototype is not invoked.
3520 // If it did we would have full access to the hidden properties in
3522 CHECK(obj->SetHiddenValue(key, v8::Integer::New(env->GetIsolate(), 42)));
3523 ExpectFalse("set_called");
3524 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value());
3528 static bool interceptor_for_hidden_properties_called;
3529 static void InterceptorForHiddenProperties(
3530 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
3531 interceptor_for_hidden_properties_called = true;
3535 THREADED_TEST(HiddenPropertiesWithInterceptors) {
3536 LocalContext context;
3537 v8::Isolate* isolate = context->GetIsolate();
3538 v8::HandleScope scope(isolate);
3540 interceptor_for_hidden_properties_called = false;
3542 v8::Local<v8::String> key = v8_str("api-test::hidden-key");
3544 // Associate an interceptor with an object and start setting hidden values.
3545 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
3546 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
3547 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
3548 Local<v8::Function> function = fun_templ->GetFunction();
3549 Local<v8::Object> obj = function->NewInstance();
3550 CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
3551 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value());
3552 CHECK(!interceptor_for_hidden_properties_called);
3556 THREADED_TEST(External) {
3557 v8::HandleScope scope(CcTest::isolate());
3559 Local<v8::External> ext = v8::External::New(CcTest::isolate(), &x);
3561 env->Global()->Set(v8_str("ext"), ext);
3562 Local<Value> reext_obj = CompileRun("this.ext");
3563 v8::Handle<v8::External> reext = reext_obj.As<v8::External>();
3564 int* ptr = static_cast<int*>(reext->Value());
3569 // Make sure unaligned pointers are wrapped properly.
3570 char* data = i::StrDup("0123456789");
3571 Local<v8::Value> zero = v8::External::New(CcTest::isolate(), &data[0]);
3572 Local<v8::Value> one = v8::External::New(CcTest::isolate(), &data[1]);
3573 Local<v8::Value> two = v8::External::New(CcTest::isolate(), &data[2]);
3574 Local<v8::Value> three = v8::External::New(CcTest::isolate(), &data[3]);
3576 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value());
3577 CHECK_EQ('0', *char_ptr);
3578 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value());
3579 CHECK_EQ('1', *char_ptr);
3580 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value());
3581 CHECK_EQ('2', *char_ptr);
3582 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value());
3583 CHECK_EQ('3', *char_ptr);
3584 i::DeleteArray(data);
3588 THREADED_TEST(GlobalHandle) {
3589 v8::Isolate* isolate = CcTest::isolate();
3590 v8::Persistent<String> global;
3592 v8::HandleScope scope(isolate);
3593 global.Reset(isolate, v8_str("str"));
3596 v8::HandleScope scope(isolate);
3597 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3601 v8::HandleScope scope(isolate);
3602 global.Reset(isolate, v8_str("str"));
3605 v8::HandleScope scope(isolate);
3606 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3612 THREADED_TEST(ResettingGlobalHandle) {
3613 v8::Isolate* isolate = CcTest::isolate();
3614 v8::Persistent<String> global;
3616 v8::HandleScope scope(isolate);
3617 global.Reset(isolate, v8_str("str"));
3619 v8::internal::GlobalHandles* global_handles =
3620 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3621 int initial_handle_count = global_handles->global_handles_count();
3623 v8::HandleScope scope(isolate);
3624 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3627 v8::HandleScope scope(isolate);
3628 global.Reset(isolate, v8_str("longer"));
3630 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count);
3632 v8::HandleScope scope(isolate);
3633 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6);
3636 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3640 THREADED_TEST(ResettingGlobalHandleToEmpty) {
3641 v8::Isolate* isolate = CcTest::isolate();
3642 v8::Persistent<String> global;
3644 v8::HandleScope scope(isolate);
3645 global.Reset(isolate, v8_str("str"));
3647 v8::internal::GlobalHandles* global_handles =
3648 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3649 int initial_handle_count = global_handles->global_handles_count();
3651 v8::HandleScope scope(isolate);
3652 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3);
3655 v8::HandleScope scope(isolate);
3656 Local<String> empty;
3657 global.Reset(isolate, empty);
3659 CHECK(global.IsEmpty());
3660 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1);
3665 static v8::UniquePersistent<T> PassUnique(v8::UniquePersistent<T> unique) {
3666 return unique.Pass();
3671 static v8::UniquePersistent<T> ReturnUnique(v8::Isolate* isolate,
3672 const v8::Persistent<T> & global) {
3673 v8::UniquePersistent<String> unique(isolate, global);
3674 return unique.Pass();
3678 THREADED_TEST(UniquePersistent) {
3679 v8::Isolate* isolate = CcTest::isolate();
3680 v8::Persistent<String> global;
3682 v8::HandleScope scope(isolate);
3683 global.Reset(isolate, v8_str("str"));
3685 v8::internal::GlobalHandles* global_handles =
3686 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3687 int initial_handle_count = global_handles->global_handles_count();
3689 v8::UniquePersistent<String> unique(isolate, global);
3690 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3691 // Test assignment via Pass
3693 v8::UniquePersistent<String> copy = unique.Pass();
3694 CHECK(unique.IsEmpty());
3695 CHECK(copy == global);
3696 CHECK_EQ(initial_handle_count + 1,
3697 global_handles->global_handles_count());
3698 unique = copy.Pass();
3700 // Test ctor via Pass
3702 v8::UniquePersistent<String> copy(unique.Pass());
3703 CHECK(unique.IsEmpty());
3704 CHECK(copy == global);
3705 CHECK_EQ(initial_handle_count + 1,
3706 global_handles->global_handles_count());
3707 unique = copy.Pass();
3709 // Test pass through function call
3711 v8::UniquePersistent<String> copy = PassUnique(unique.Pass());
3712 CHECK(unique.IsEmpty());
3713 CHECK(copy == global);
3714 CHECK_EQ(initial_handle_count + 1,
3715 global_handles->global_handles_count());
3716 unique = copy.Pass();
3718 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3720 // Test pass from function call
3722 v8::UniquePersistent<String> unique = ReturnUnique(isolate, global);
3723 CHECK(unique == global);
3724 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3726 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3731 template<typename K, typename V>
3732 class WeakStdMapTraits : public v8::StdMapTraits<K, V> {
3734 typedef typename v8::PersistentValueMap<K, V, WeakStdMapTraits<K, V> >
3736 static const v8::PersistentContainerCallbackType kCallbackType = v8::kWeak;
3737 struct WeakCallbackDataType {
3741 static WeakCallbackDataType* WeakCallbackParameter(
3742 MapType* map, const K& key, Local<V> value) {
3743 WeakCallbackDataType* data = new WeakCallbackDataType;
3748 static MapType* MapFromWeakCallbackData(
3749 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3750 return data.GetParameter()->map;
3752 static K KeyFromWeakCallbackData(
3753 const v8::WeakCallbackData<V, WeakCallbackDataType>& data) {
3754 return data.GetParameter()->key;
3756 static void DisposeCallbackData(WeakCallbackDataType* data) {
3759 static void Dispose(v8::Isolate* isolate, v8::UniquePersistent<V> value,
3764 template<typename Map>
3765 static void TestPersistentValueMap() {
3767 v8::Isolate* isolate = env->GetIsolate();
3769 v8::internal::GlobalHandles* global_handles =
3770 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3771 int initial_handle_count = global_handles->global_handles_count();
3772 CHECK_EQ(0, static_cast<int>(map.Size()));
3774 HandleScope scope(isolate);
3775 Local<v8::Object> obj = map.Get(7);
3776 CHECK(obj.IsEmpty());
3777 Local<v8::Object> expected = v8::Object::New(isolate);
3778 map.Set(7, expected);
3779 CHECK_EQ(1, static_cast<int>(map.Size()));
3781 CHECK_EQ(expected, obj);
3783 typename Map::PersistentValueReference ref = map.GetReference(7);
3784 CHECK_EQ(expected, ref.NewLocal(isolate));
3786 v8::UniquePersistent<v8::Object> removed = map.Remove(7);
3787 CHECK_EQ(0, static_cast<int>(map.Size()));
3788 CHECK(expected == removed);
3789 removed = map.Remove(7);
3790 CHECK(removed.IsEmpty());
3791 map.Set(8, expected);
3792 CHECK_EQ(1, static_cast<int>(map.Size()));
3793 map.Set(8, expected);
3794 CHECK_EQ(1, static_cast<int>(map.Size()));
3796 typename Map::PersistentValueReference ref;
3797 Local<v8::Object> expected2 = v8::Object::New(isolate);
3798 removed = map.Set(8,
3799 v8::UniquePersistent<v8::Object>(isolate, expected2), &ref);
3800 CHECK_EQ(1, static_cast<int>(map.Size()));
3801 CHECK(expected == removed);
3802 CHECK_EQ(expected2, ref.NewLocal(isolate));
3805 CHECK_EQ(initial_handle_count + 1, global_handles->global_handles_count());
3807 reinterpret_cast<v8::internal::Isolate*>(isolate)->heap()->
3808 CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
3812 CHECK_EQ(0, static_cast<int>(map.Size()));
3813 CHECK_EQ(initial_handle_count, global_handles->global_handles_count());
3817 TEST(PersistentValueMap) {
3818 // Default case, w/o weak callbacks:
3819 TestPersistentValueMap<v8::StdPersistentValueMap<int, v8::Object> >();
3821 // Custom traits with weak callbacks:
3822 typedef v8::PersistentValueMap<int, v8::Object,
3823 WeakStdMapTraits<int, v8::Object> > WeakPersistentValueMap;
3824 TestPersistentValueMap<WeakPersistentValueMap>();
3828 TEST(PersistentValueVector) {
3830 v8::Isolate* isolate = env->GetIsolate();
3831 v8::internal::GlobalHandles* global_handles =
3832 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles();
3833 int handle_count = global_handles->global_handles_count();
3834 HandleScope scope(isolate);
3836 v8::PersistentValueVector<v8::Object> vector(isolate);
3838 Local<v8::Object> obj1 = v8::Object::New(isolate);
3839 Local<v8::Object> obj2 = v8::Object::New(isolate);
3840 v8::UniquePersistent<v8::Object> obj3(isolate, v8::Object::New(isolate));
3842 CHECK(vector.IsEmpty());
3843 CHECK_EQ(0, static_cast<int>(vector.Size()));
3845 vector.ReserveCapacity(3);
3846 CHECK(vector.IsEmpty());
3848 vector.Append(obj1);
3849 vector.Append(obj2);
3850 vector.Append(obj1);
3851 vector.Append(obj3.Pass());
3852 vector.Append(obj1);
3854 CHECK(!vector.IsEmpty());
3855 CHECK_EQ(5, static_cast<int>(vector.Size()));
3856 CHECK(obj3.IsEmpty());
3857 CHECK_EQ(obj1, vector.Get(0));
3858 CHECK_EQ(obj1, vector.Get(2));
3859 CHECK_EQ(obj1, vector.Get(4));
3860 CHECK_EQ(obj2, vector.Get(1));
3862 CHECK_EQ(5 + handle_count, global_handles->global_handles_count());
3865 CHECK(vector.IsEmpty());
3866 CHECK_EQ(0, static_cast<int>(vector.Size()));
3867 CHECK_EQ(handle_count, global_handles->global_handles_count());
3871 THREADED_TEST(GlobalHandleUpcast) {
3872 v8::Isolate* isolate = CcTest::isolate();
3873 v8::HandleScope scope(isolate);
3874 v8::Local<String> local = v8::Local<String>::New(isolate, v8_str("str"));
3875 v8::Persistent<String> global_string(isolate, local);
3876 v8::Persistent<Value>& global_value =
3877 v8::Persistent<Value>::Cast(global_string);
3878 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString());
3879 CHECK(global_string == v8::Persistent<String>::Cast(global_value));
3880 global_string.Reset();
3884 THREADED_TEST(HandleEquality) {
3885 v8::Isolate* isolate = CcTest::isolate();
3886 v8::Persistent<String> global1;
3887 v8::Persistent<String> global2;
3889 v8::HandleScope scope(isolate);
3890 global1.Reset(isolate, v8_str("str"));
3891 global2.Reset(isolate, v8_str("str2"));
3893 CHECK_EQ(global1 == global1, true);
3894 CHECK_EQ(global1 != global1, false);
3896 v8::HandleScope scope(isolate);
3897 Local<String> local1 = Local<String>::New(isolate, global1);
3898 Local<String> local2 = Local<String>::New(isolate, global2);
3900 CHECK_EQ(global1 == local1, true);
3901 CHECK_EQ(global1 != local1, false);
3902 CHECK_EQ(local1 == global1, true);
3903 CHECK_EQ(local1 != global1, false);
3905 CHECK_EQ(global1 == local2, false);
3906 CHECK_EQ(global1 != local2, true);
3907 CHECK_EQ(local2 == global1, false);
3908 CHECK_EQ(local2 != global1, true);
3910 CHECK_EQ(local1 == local2, false);
3911 CHECK_EQ(local1 != local2, true);
3913 Local<String> anotherLocal1 = Local<String>::New(isolate, global1);
3914 CHECK_EQ(local1 == anotherLocal1, true);
3915 CHECK_EQ(local1 != anotherLocal1, false);
3922 THREADED_TEST(LocalHandle) {
3923 v8::HandleScope scope(CcTest::isolate());
3924 v8::Local<String> local =
3925 v8::Local<String>::New(CcTest::isolate(), v8_str("str"));
3926 CHECK_EQ(local->Length(), 3);
3930 class WeakCallCounter {
3932 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { }
3933 int id() { return id_; }
3934 void increment() { number_of_weak_calls_++; }
3935 int NumberOfWeakCalls() { return number_of_weak_calls_; }
3938 int number_of_weak_calls_;
3942 template<typename T>
3943 struct WeakCallCounterAndPersistent {
3944 explicit WeakCallCounterAndPersistent(WeakCallCounter* counter)
3945 : counter(counter) {}
3946 WeakCallCounter* counter;
3947 v8::Persistent<T> handle;
3951 template <typename T>
3952 static void WeakPointerCallback(
3953 const v8::WeakCallbackData<T, WeakCallCounterAndPersistent<T> >& data) {
3954 CHECK_EQ(1234, data.GetParameter()->counter->id());
3955 data.GetParameter()->counter->increment();
3956 data.GetParameter()->handle.Reset();
3960 template<typename T>
3961 static UniqueId MakeUniqueId(const Persistent<T>& p) {
3962 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p)));
3966 THREADED_TEST(ApiObjectGroups) {
3968 v8::Isolate* iso = env->GetIsolate();
3969 HandleScope scope(iso);
3971 WeakCallCounter counter(1234);
3973 WeakCallCounterAndPersistent<Value> g1s1(&counter);
3974 WeakCallCounterAndPersistent<Value> g1s2(&counter);
3975 WeakCallCounterAndPersistent<Value> g1c1(&counter);
3976 WeakCallCounterAndPersistent<Value> g2s1(&counter);
3977 WeakCallCounterAndPersistent<Value> g2s2(&counter);
3978 WeakCallCounterAndPersistent<Value> g2c1(&counter);
3981 HandleScope scope(iso);
3982 g1s1.handle.Reset(iso, Object::New(iso));
3983 g1s2.handle.Reset(iso, Object::New(iso));
3984 g1c1.handle.Reset(iso, Object::New(iso));
3985 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
3986 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
3987 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
3989 g2s1.handle.Reset(iso, Object::New(iso));
3990 g2s2.handle.Reset(iso, Object::New(iso));
3991 g2c1.handle.Reset(iso, Object::New(iso));
3992 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
3993 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
3994 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
3997 WeakCallCounterAndPersistent<Value> root(&counter);
3998 root.handle.Reset(iso, g1s1.handle); // make a root.
4000 // Connect group 1 and 2, make a cycle.
4002 HandleScope scope(iso);
4003 CHECK(Local<Object>::New(iso, g1s2.handle.As<Object>())->
4004 Set(0, Local<Value>::New(iso, g2s2.handle)));
4005 CHECK(Local<Object>::New(iso, g2s1.handle.As<Object>())->
4006 Set(0, Local<Value>::New(iso, g1s1.handle)));
4010 UniqueId id1 = MakeUniqueId(g1s1.handle);
4011 UniqueId id2 = MakeUniqueId(g2s2.handle);
4012 iso->SetObjectGroupId(g1s1.handle, id1);
4013 iso->SetObjectGroupId(g1s2.handle, id1);
4014 iso->SetReferenceFromGroup(id1, g1c1.handle);
4015 iso->SetObjectGroupId(g2s1.handle, id2);
4016 iso->SetObjectGroupId(g2s2.handle, id2);
4017 iso->SetReferenceFromGroup(id2, g2c1.handle);
4019 // Do a single full GC, ensure incremental marking is stopped.
4020 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4022 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4024 // All object should be alive.
4025 CHECK_EQ(0, counter.NumberOfWeakCalls());
4028 root.handle.SetWeak(&root, &WeakPointerCallback);
4029 // But make children strong roots---all the objects (except for children)
4030 // should be collectable now.
4031 g1c1.handle.ClearWeak();
4032 g2c1.handle.ClearWeak();
4034 // Groups are deleted, rebuild groups.
4036 UniqueId id1 = MakeUniqueId(g1s1.handle);
4037 UniqueId id2 = MakeUniqueId(g2s2.handle);
4038 iso->SetObjectGroupId(g1s1.handle, id1);
4039 iso->SetObjectGroupId(g1s2.handle, id1);
4040 iso->SetReferenceFromGroup(id1, g1c1.handle);
4041 iso->SetObjectGroupId(g2s1.handle, id2);
4042 iso->SetObjectGroupId(g2s2.handle, id2);
4043 iso->SetReferenceFromGroup(id2, g2c1.handle);
4046 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4048 // All objects should be gone. 5 global handles in total.
4049 CHECK_EQ(5, counter.NumberOfWeakCalls());
4051 // And now make children weak again and collect them.
4052 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4053 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4055 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4056 CHECK_EQ(7, counter.NumberOfWeakCalls());
4060 THREADED_TEST(ApiObjectGroupsForSubtypes) {
4062 v8::Isolate* iso = env->GetIsolate();
4063 HandleScope scope(iso);
4065 WeakCallCounter counter(1234);
4067 WeakCallCounterAndPersistent<Object> g1s1(&counter);
4068 WeakCallCounterAndPersistent<String> g1s2(&counter);
4069 WeakCallCounterAndPersistent<String> g1c1(&counter);
4070 WeakCallCounterAndPersistent<Object> g2s1(&counter);
4071 WeakCallCounterAndPersistent<String> g2s2(&counter);
4072 WeakCallCounterAndPersistent<String> g2c1(&counter);
4075 HandleScope scope(iso);
4076 g1s1.handle.Reset(iso, Object::New(iso));
4077 g1s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo1"));
4078 g1c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo2"));
4079 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4080 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4081 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4083 g2s1.handle.Reset(iso, Object::New(iso));
4084 g2s2.handle.Reset(iso, String::NewFromUtf8(iso, "foo3"));
4085 g2c1.handle.Reset(iso, String::NewFromUtf8(iso, "foo4"));
4086 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4087 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4088 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4091 WeakCallCounterAndPersistent<Value> root(&counter);
4092 root.handle.Reset(iso, g1s1.handle); // make a root.
4094 // Connect group 1 and 2, make a cycle.
4096 HandleScope scope(iso);
4097 CHECK(Local<Object>::New(iso, g1s1.handle)
4098 ->Set(0, Local<Object>::New(iso, g2s1.handle)));
4099 CHECK(Local<Object>::New(iso, g2s1.handle)
4100 ->Set(0, Local<Object>::New(iso, g1s1.handle)));
4104 UniqueId id1 = MakeUniqueId(g1s1.handle);
4105 UniqueId id2 = MakeUniqueId(g2s2.handle);
4106 iso->SetObjectGroupId(g1s1.handle, id1);
4107 iso->SetObjectGroupId(g1s2.handle, id1);
4108 iso->SetReference(g1s1.handle, g1c1.handle);
4109 iso->SetObjectGroupId(g2s1.handle, id2);
4110 iso->SetObjectGroupId(g2s2.handle, id2);
4111 iso->SetReferenceFromGroup(id2, g2c1.handle);
4113 // Do a single full GC, ensure incremental marking is stopped.
4114 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4116 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4118 // All object should be alive.
4119 CHECK_EQ(0, counter.NumberOfWeakCalls());
4122 root.handle.SetWeak(&root, &WeakPointerCallback);
4123 // But make children strong roots---all the objects (except for children)
4124 // should be collectable now.
4125 g1c1.handle.ClearWeak();
4126 g2c1.handle.ClearWeak();
4128 // Groups are deleted, rebuild groups.
4130 UniqueId id1 = MakeUniqueId(g1s1.handle);
4131 UniqueId id2 = MakeUniqueId(g2s2.handle);
4132 iso->SetObjectGroupId(g1s1.handle, id1);
4133 iso->SetObjectGroupId(g1s2.handle, id1);
4134 iso->SetReference(g1s1.handle, g1c1.handle);
4135 iso->SetObjectGroupId(g2s1.handle, id2);
4136 iso->SetObjectGroupId(g2s2.handle, id2);
4137 iso->SetReferenceFromGroup(id2, g2c1.handle);
4140 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4142 // All objects should be gone. 5 global handles in total.
4143 CHECK_EQ(5, counter.NumberOfWeakCalls());
4145 // And now make children weak again and collect them.
4146 g1c1.handle.SetWeak(&g1c1, &WeakPointerCallback);
4147 g2c1.handle.SetWeak(&g2c1, &WeakPointerCallback);
4149 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4150 CHECK_EQ(7, counter.NumberOfWeakCalls());
4154 THREADED_TEST(ApiObjectGroupsCycle) {
4156 v8::Isolate* iso = env->GetIsolate();
4157 HandleScope scope(iso);
4159 WeakCallCounter counter(1234);
4161 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4162 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4163 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4164 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4165 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4166 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4167 WeakCallCounterAndPersistent<Value> g4s1(&counter);
4168 WeakCallCounterAndPersistent<Value> g4s2(&counter);
4171 HandleScope scope(iso);
4172 g1s1.handle.Reset(iso, Object::New(iso));
4173 g1s2.handle.Reset(iso, Object::New(iso));
4174 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4175 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4176 CHECK(g1s1.handle.IsWeak());
4177 CHECK(g1s2.handle.IsWeak());
4179 g2s1.handle.Reset(iso, Object::New(iso));
4180 g2s2.handle.Reset(iso, Object::New(iso));
4181 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4182 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4183 CHECK(g2s1.handle.IsWeak());
4184 CHECK(g2s2.handle.IsWeak());
4186 g3s1.handle.Reset(iso, Object::New(iso));
4187 g3s2.handle.Reset(iso, Object::New(iso));
4188 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4189 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4190 CHECK(g3s1.handle.IsWeak());
4191 CHECK(g3s2.handle.IsWeak());
4193 g4s1.handle.Reset(iso, Object::New(iso));
4194 g4s2.handle.Reset(iso, Object::New(iso));
4195 g4s1.handle.SetWeak(&g4s1, &WeakPointerCallback);
4196 g4s2.handle.SetWeak(&g4s2, &WeakPointerCallback);
4197 CHECK(g4s1.handle.IsWeak());
4198 CHECK(g4s2.handle.IsWeak());
4201 WeakCallCounterAndPersistent<Value> root(&counter);
4202 root.handle.Reset(iso, g1s1.handle); // make a root.
4204 // Connect groups. We're building the following cycle:
4205 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4208 UniqueId id1 = MakeUniqueId(g1s1.handle);
4209 UniqueId id2 = MakeUniqueId(g2s1.handle);
4210 UniqueId id3 = MakeUniqueId(g3s1.handle);
4211 UniqueId id4 = MakeUniqueId(g4s1.handle);
4212 iso->SetObjectGroupId(g1s1.handle, id1);
4213 iso->SetObjectGroupId(g1s2.handle, id1);
4214 iso->SetReferenceFromGroup(id1, g2s1.handle);
4215 iso->SetObjectGroupId(g2s1.handle, id2);
4216 iso->SetObjectGroupId(g2s2.handle, id2);
4217 iso->SetReferenceFromGroup(id2, g3s1.handle);
4218 iso->SetObjectGroupId(g3s1.handle, id3);
4219 iso->SetObjectGroupId(g3s2.handle, id3);
4220 iso->SetReferenceFromGroup(id3, g4s1.handle);
4221 iso->SetObjectGroupId(g4s1.handle, id4);
4222 iso->SetObjectGroupId(g4s2.handle, id4);
4223 iso->SetReferenceFromGroup(id4, g1s1.handle);
4225 // Do a single full GC
4226 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4228 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4230 // All object should be alive.
4231 CHECK_EQ(0, counter.NumberOfWeakCalls());
4234 root.handle.SetWeak(&root, &WeakPointerCallback);
4236 // Groups are deleted, rebuild groups.
4238 UniqueId id1 = MakeUniqueId(g1s1.handle);
4239 UniqueId id2 = MakeUniqueId(g2s1.handle);
4240 UniqueId id3 = MakeUniqueId(g3s1.handle);
4241 UniqueId id4 = MakeUniqueId(g4s1.handle);
4242 iso->SetObjectGroupId(g1s1.handle, id1);
4243 iso->SetObjectGroupId(g1s2.handle, id1);
4244 iso->SetReferenceFromGroup(id1, g2s1.handle);
4245 iso->SetObjectGroupId(g2s1.handle, id2);
4246 iso->SetObjectGroupId(g2s2.handle, id2);
4247 iso->SetReferenceFromGroup(id2, g3s1.handle);
4248 iso->SetObjectGroupId(g3s1.handle, id3);
4249 iso->SetObjectGroupId(g3s2.handle, id3);
4250 iso->SetReferenceFromGroup(id3, g4s1.handle);
4251 iso->SetObjectGroupId(g4s1.handle, id4);
4252 iso->SetObjectGroupId(g4s2.handle, id4);
4253 iso->SetReferenceFromGroup(id4, g1s1.handle);
4256 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
4258 // All objects should be gone. 9 global handles in total.
4259 CHECK_EQ(9, counter.NumberOfWeakCalls());
4263 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
4264 // on the buildbots, so was made non-threaded for the time being.
4265 TEST(ApiObjectGroupsCycleForScavenger) {
4266 i::FLAG_stress_compaction = false;
4267 i::FLAG_gc_global = false;
4269 v8::Isolate* iso = env->GetIsolate();
4270 HandleScope scope(iso);
4272 WeakCallCounter counter(1234);
4274 WeakCallCounterAndPersistent<Value> g1s1(&counter);
4275 WeakCallCounterAndPersistent<Value> g1s2(&counter);
4276 WeakCallCounterAndPersistent<Value> g2s1(&counter);
4277 WeakCallCounterAndPersistent<Value> g2s2(&counter);
4278 WeakCallCounterAndPersistent<Value> g3s1(&counter);
4279 WeakCallCounterAndPersistent<Value> g3s2(&counter);
4282 HandleScope scope(iso);
4283 g1s1.handle.Reset(iso, Object::New(iso));
4284 g1s2.handle.Reset(iso, Object::New(iso));
4285 g1s1.handle.SetWeak(&g1s1, &WeakPointerCallback);
4286 g1s2.handle.SetWeak(&g1s2, &WeakPointerCallback);
4288 g2s1.handle.Reset(iso, Object::New(iso));
4289 g2s2.handle.Reset(iso, Object::New(iso));
4290 g2s1.handle.SetWeak(&g2s1, &WeakPointerCallback);
4291 g2s2.handle.SetWeak(&g2s2, &WeakPointerCallback);
4293 g3s1.handle.Reset(iso, Object::New(iso));
4294 g3s2.handle.Reset(iso, Object::New(iso));
4295 g3s1.handle.SetWeak(&g3s1, &WeakPointerCallback);
4296 g3s2.handle.SetWeak(&g3s2, &WeakPointerCallback);
4300 WeakCallCounterAndPersistent<Value> root(&counter);
4301 root.handle.Reset(iso, g1s1.handle);
4302 root.handle.MarkPartiallyDependent();
4304 // Connect groups. We're building the following cycle:
4305 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other
4308 HandleScope handle_scope(iso);
4309 g1s1.handle.MarkPartiallyDependent();
4310 g1s2.handle.MarkPartiallyDependent();
4311 g2s1.handle.MarkPartiallyDependent();
4312 g2s2.handle.MarkPartiallyDependent();
4313 g3s1.handle.MarkPartiallyDependent();
4314 g3s2.handle.MarkPartiallyDependent();
4315 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4316 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4317 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4318 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4319 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4320 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4321 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4322 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4323 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4324 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4325 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4326 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4329 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>(
4331 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4333 // All objects should be alive.
4334 CHECK_EQ(0, counter.NumberOfWeakCalls());
4337 root.handle.SetWeak(&root, &WeakPointerCallback);
4338 root.handle.MarkPartiallyDependent();
4340 // Groups are deleted, rebuild groups.
4342 HandleScope handle_scope(iso);
4343 g1s1.handle.MarkPartiallyDependent();
4344 g1s2.handle.MarkPartiallyDependent();
4345 g2s1.handle.MarkPartiallyDependent();
4346 g2s2.handle.MarkPartiallyDependent();
4347 g3s1.handle.MarkPartiallyDependent();
4348 g3s2.handle.MarkPartiallyDependent();
4349 iso->SetObjectGroupId(g1s1.handle, UniqueId(1));
4350 iso->SetObjectGroupId(g1s2.handle, UniqueId(1));
4351 Local<Object>::New(iso, g1s1.handle.As<Object>())->Set(
4352 v8_str("x"), Local<Value>::New(iso, g2s1.handle));
4353 iso->SetObjectGroupId(g2s1.handle, UniqueId(2));
4354 iso->SetObjectGroupId(g2s2.handle, UniqueId(2));
4355 Local<Object>::New(iso, g2s1.handle.As<Object>())->Set(
4356 v8_str("x"), Local<Value>::New(iso, g3s1.handle));
4357 iso->SetObjectGroupId(g3s1.handle, UniqueId(3));
4358 iso->SetObjectGroupId(g3s2.handle, UniqueId(3));
4359 Local<Object>::New(iso, g3s1.handle.As<Object>())->Set(
4360 v8_str("x"), Local<Value>::New(iso, g1s1.handle));
4363 heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4365 // All objects should be gone. 7 global handles in total.
4366 CHECK_EQ(7, counter.NumberOfWeakCalls());
4370 THREADED_TEST(ScriptException) {
4372 v8::HandleScope scope(env->GetIsolate());
4373 Local<Script> script = v8_compile("throw 'panama!';");
4374 v8::TryCatch try_catch;
4375 Local<Value> result = script->Run();
4376 CHECK(result.IsEmpty());
4377 CHECK(try_catch.HasCaught());
4378 String::Utf8Value exception_value(try_catch.Exception());
4379 CHECK_EQ(*exception_value, "panama!");
4383 TEST(TryCatchCustomException) {
4385 v8::HandleScope scope(env->GetIsolate());
4386 v8::TryCatch try_catch;
4387 CompileRun("function CustomError() { this.a = 'b'; }"
4388 "(function f() { throw new CustomError(); })();");
4389 CHECK(try_catch.HasCaught());
4390 CHECK(try_catch.Exception()->ToObject()->
4391 Get(v8_str("a"))->Equals(v8_str("b")));
4395 bool message_received;
4398 static void check_message_0(v8::Handle<v8::Message> message,
4399 v8::Handle<Value> data) {
4400 CHECK_EQ(5.76, data->NumberValue());
4401 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4402 CHECK(!message->IsSharedCrossOrigin());
4403 message_received = true;
4407 THREADED_TEST(MessageHandler0) {
4408 message_received = false;
4409 v8::HandleScope scope(CcTest::isolate());
4410 CHECK(!message_received);
4411 LocalContext context;
4412 v8::V8::AddMessageListener(check_message_0, v8_num(5.76));
4413 v8::Handle<v8::Script> script = CompileWithOrigin("throw 'error'", "6.75");
4415 CHECK(message_received);
4416 // clear out the message listener
4417 v8::V8::RemoveMessageListeners(check_message_0);
4421 static void check_message_1(v8::Handle<v8::Message> message,
4422 v8::Handle<Value> data) {
4423 CHECK(data->IsNumber());
4424 CHECK_EQ(1337, data->Int32Value());
4425 CHECK(!message->IsSharedCrossOrigin());
4426 message_received = true;
4430 TEST(MessageHandler1) {
4431 message_received = false;
4432 v8::HandleScope scope(CcTest::isolate());
4433 CHECK(!message_received);
4434 v8::V8::AddMessageListener(check_message_1);
4435 LocalContext context;
4436 CompileRun("throw 1337;");
4437 CHECK(message_received);
4438 // clear out the message listener
4439 v8::V8::RemoveMessageListeners(check_message_1);
4443 static void check_message_2(v8::Handle<v8::Message> message,
4444 v8::Handle<Value> data) {
4445 LocalContext context;
4446 CHECK(data->IsObject());
4447 v8::Local<v8::Value> hidden_property =
4448 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key"));
4449 CHECK(v8_str("hidden value")->Equals(hidden_property));
4450 CHECK(!message->IsSharedCrossOrigin());
4451 message_received = true;
4455 TEST(MessageHandler2) {
4456 message_received = false;
4457 v8::HandleScope scope(CcTest::isolate());
4458 CHECK(!message_received);
4459 v8::V8::AddMessageListener(check_message_2);
4460 LocalContext context;
4461 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error"));
4462 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"),
4463 v8_str("hidden value"));
4464 context->Global()->Set(v8_str("error"), error);
4465 CompileRun("throw error;");
4466 CHECK(message_received);
4467 // clear out the message listener
4468 v8::V8::RemoveMessageListeners(check_message_2);
4472 static void check_message_3(v8::Handle<v8::Message> message,
4473 v8::Handle<Value> data) {
4474 CHECK(message->IsSharedCrossOrigin());
4475 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4476 message_received = true;
4480 TEST(MessageHandler3) {
4481 message_received = false;
4482 v8::Isolate* isolate = CcTest::isolate();
4483 v8::HandleScope scope(isolate);
4484 CHECK(!message_received);
4485 v8::V8::AddMessageListener(check_message_3);
4486 LocalContext context;
4487 v8::ScriptOrigin origin =
4488 v8::ScriptOrigin(v8_str("6.75"),
4489 v8::Integer::New(isolate, 1),
4490 v8::Integer::New(isolate, 2),
4492 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4495 CHECK(message_received);
4496 // clear out the message listener
4497 v8::V8::RemoveMessageListeners(check_message_3);
4501 static void check_message_4(v8::Handle<v8::Message> message,
4502 v8::Handle<Value> data) {
4503 CHECK(!message->IsSharedCrossOrigin());
4504 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4505 message_received = true;
4509 TEST(MessageHandler4) {
4510 message_received = false;
4511 v8::Isolate* isolate = CcTest::isolate();
4512 v8::HandleScope scope(isolate);
4513 CHECK(!message_received);
4514 v8::V8::AddMessageListener(check_message_4);
4515 LocalContext context;
4516 v8::ScriptOrigin origin =
4517 v8::ScriptOrigin(v8_str("6.75"),
4518 v8::Integer::New(isolate, 1),
4519 v8::Integer::New(isolate, 2),
4520 v8::False(isolate));
4521 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4524 CHECK(message_received);
4525 // clear out the message listener
4526 v8::V8::RemoveMessageListeners(check_message_4);
4530 static void check_message_5a(v8::Handle<v8::Message> message,
4531 v8::Handle<Value> data) {
4532 CHECK(message->IsSharedCrossOrigin());
4533 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4534 message_received = true;
4538 static void check_message_5b(v8::Handle<v8::Message> message,
4539 v8::Handle<Value> data) {
4540 CHECK(!message->IsSharedCrossOrigin());
4541 CHECK_EQ(6.75, message->GetScriptOrigin().ResourceName()->NumberValue());
4542 message_received = true;
4546 TEST(MessageHandler5) {
4547 message_received = false;
4548 v8::Isolate* isolate = CcTest::isolate();
4549 v8::HandleScope scope(isolate);
4550 CHECK(!message_received);
4551 v8::V8::AddMessageListener(check_message_5a);
4552 LocalContext context;
4553 v8::ScriptOrigin origin =
4554 v8::ScriptOrigin(v8_str("6.75"),
4555 v8::Integer::New(isolate, 1),
4556 v8::Integer::New(isolate, 2),
4558 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"),
4561 CHECK(message_received);
4562 // clear out the message listener
4563 v8::V8::RemoveMessageListeners(check_message_5a);
4565 message_received = false;
4566 v8::V8::AddMessageListener(check_message_5b);
4568 v8::ScriptOrigin(v8_str("6.75"),
4569 v8::Integer::New(isolate, 1),
4570 v8::Integer::New(isolate, 2),
4571 v8::False(isolate));
4572 script = Script::Compile(v8_str("throw 'error'"),
4575 CHECK(message_received);
4576 // clear out the message listener
4577 v8::V8::RemoveMessageListeners(check_message_5b);
4581 THREADED_TEST(GetSetProperty) {
4582 LocalContext context;
4583 v8::Isolate* isolate = context->GetIsolate();
4584 v8::HandleScope scope(isolate);
4585 context->Global()->Set(v8_str("foo"), v8_num(14));
4586 context->Global()->Set(v8_str("12"), v8_num(92));
4587 context->Global()->Set(v8::Integer::New(isolate, 16), v8_num(32));
4588 context->Global()->Set(v8_num(13), v8_num(56));
4589 Local<Value> foo = CompileRun("this.foo");
4590 CHECK_EQ(14, foo->Int32Value());
4591 Local<Value> twelve = CompileRun("this[12]");
4592 CHECK_EQ(92, twelve->Int32Value());
4593 Local<Value> sixteen = CompileRun("this[16]");
4594 CHECK_EQ(32, sixteen->Int32Value());
4595 Local<Value> thirteen = CompileRun("this[13]");
4596 CHECK_EQ(56, thirteen->Int32Value());
4598 context->Global()->Get(v8::Integer::New(isolate, 12))->Int32Value());
4599 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value());
4600 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value());
4602 context->Global()->Get(v8::Integer::New(isolate, 16))->Int32Value());
4603 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value());
4604 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value());
4606 context->Global()->Get(v8::Integer::New(isolate, 13))->Int32Value());
4607 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value());
4608 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value());
4612 THREADED_TEST(PropertyAttributes) {
4613 LocalContext context;
4614 v8::HandleScope scope(context->GetIsolate());
4616 Local<String> prop = v8_str("none");
4617 context->Global()->Set(prop, v8_num(7));
4618 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4620 prop = v8_str("read_only");
4621 context->Global()->ForceSet(prop, v8_num(7), v8::ReadOnly);
4622 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4623 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop));
4624 CompileRun("read_only = 9");
4625 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4626 context->Global()->Set(prop, v8_num(10));
4627 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value());
4629 prop = v8_str("dont_delete");
4630 context->Global()->ForceSet(prop, v8_num(13), v8::DontDelete);
4631 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4632 CompileRun("delete dont_delete");
4633 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value());
4634 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop));
4636 prop = v8_str("dont_enum");
4637 context->Global()->ForceSet(prop, v8_num(28), v8::DontEnum);
4638 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop));
4640 prop = v8_str("absent");
4641 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop));
4642 Local<Value> fake_prop = v8_num(1);
4643 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop));
4646 Local<Value> exception =
4647 CompileRun("({ toString: function() { throw 'exception';} })");
4648 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception));
4649 CHECK(try_catch.HasCaught());
4650 String::Utf8Value exception_value(try_catch.Exception());
4651 CHECK_EQ("exception", *exception_value);
4656 THREADED_TEST(Array) {
4657 LocalContext context;
4658 v8::HandleScope scope(context->GetIsolate());
4659 Local<v8::Array> array = v8::Array::New(context->GetIsolate());
4660 CHECK_EQ(0, array->Length());
4661 CHECK(array->Get(0)->IsUndefined());
4662 CHECK(!array->Has(0));
4663 CHECK(array->Get(100)->IsUndefined());
4664 CHECK(!array->Has(100));
4665 array->Set(2, v8_num(7));
4666 CHECK_EQ(3, array->Length());
4667 CHECK(!array->Has(0));
4668 CHECK(!array->Has(1));
4669 CHECK(array->Has(2));
4670 CHECK_EQ(7, array->Get(2)->Int32Value());
4671 Local<Value> obj = CompileRun("[1, 2, 3]");
4672 Local<v8::Array> arr = obj.As<v8::Array>();
4673 CHECK_EQ(3, arr->Length());
4674 CHECK_EQ(1, arr->Get(0)->Int32Value());
4675 CHECK_EQ(2, arr->Get(1)->Int32Value());
4676 CHECK_EQ(3, arr->Get(2)->Int32Value());
4677 array = v8::Array::New(context->GetIsolate(), 27);
4678 CHECK_EQ(27, array->Length());
4679 array = v8::Array::New(context->GetIsolate(), -27);
4680 CHECK_EQ(0, array->Length());
4684 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) {
4685 v8::EscapableHandleScope scope(args.GetIsolate());
4686 ApiTestFuzzer::Fuzz();
4687 Local<v8::Array> result = v8::Array::New(args.GetIsolate(), args.Length());
4688 for (int i = 0; i < args.Length(); i++)
4689 result->Set(i, args[i]);
4690 args.GetReturnValue().Set(scope.Escape(result));
4694 THREADED_TEST(Vector) {
4695 v8::Isolate* isolate = CcTest::isolate();
4696 v8::HandleScope scope(isolate);
4697 Local<ObjectTemplate> global = ObjectTemplate::New(isolate);
4698 global->Set(v8_str("f"), v8::FunctionTemplate::New(isolate, HandleF));
4699 LocalContext context(0, global);
4701 const char* fun = "f()";
4702 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>();
4703 CHECK_EQ(0, a0->Length());
4705 const char* fun2 = "f(11)";
4706 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>();
4707 CHECK_EQ(1, a1->Length());
4708 CHECK_EQ(11, a1->Get(0)->Int32Value());
4710 const char* fun3 = "f(12, 13)";
4711 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>();
4712 CHECK_EQ(2, a2->Length());
4713 CHECK_EQ(12, a2->Get(0)->Int32Value());
4714 CHECK_EQ(13, a2->Get(1)->Int32Value());
4716 const char* fun4 = "f(14, 15, 16)";
4717 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>();
4718 CHECK_EQ(3, a3->Length());
4719 CHECK_EQ(14, a3->Get(0)->Int32Value());
4720 CHECK_EQ(15, a3->Get(1)->Int32Value());
4721 CHECK_EQ(16, a3->Get(2)->Int32Value());
4723 const char* fun5 = "f(17, 18, 19, 20)";
4724 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>();
4725 CHECK_EQ(4, a4->Length());
4726 CHECK_EQ(17, a4->Get(0)->Int32Value());
4727 CHECK_EQ(18, a4->Get(1)->Int32Value());
4728 CHECK_EQ(19, a4->Get(2)->Int32Value());
4729 CHECK_EQ(20, a4->Get(3)->Int32Value());
4733 THREADED_TEST(FunctionCall) {
4734 LocalContext context;
4735 v8::Isolate* isolate = context->GetIsolate();
4736 v8::HandleScope scope(isolate);
4740 " for (var i = 0; i < arguments.length; i++) {"
4741 " result.push(arguments[i]);"
4745 "function ReturnThisSloppy() {"
4748 "function ReturnThisStrict() {"
4752 Local<Function> Foo =
4753 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4754 Local<Function> ReturnThisSloppy =
4755 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
4756 Local<Function> ReturnThisStrict =
4757 Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
4759 v8::Handle<Value>* args0 = NULL;
4760 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
4761 CHECK_EQ(0, a0->Length());
4763 v8::Handle<Value> args1[] = { v8_num(1.1) };
4764 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1));
4765 CHECK_EQ(1, a1->Length());
4766 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4768 v8::Handle<Value> args2[] = { v8_num(2.2),
4770 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2));
4771 CHECK_EQ(2, a2->Length());
4772 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4773 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4775 v8::Handle<Value> args3[] = { v8_num(4.4),
4778 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3));
4779 CHECK_EQ(3, a3->Length());
4780 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4781 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4782 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4784 v8::Handle<Value> args4[] = { v8_num(7.7),
4788 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4));
4789 CHECK_EQ(4, a4->Length());
4790 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4791 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4792 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4793 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4795 Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
4796 CHECK(r1->StrictEquals(context->Global()));
4797 Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
4798 CHECK(r2->StrictEquals(context->Global()));
4799 Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
4800 CHECK(r3->IsNumberObject());
4801 CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
4802 Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
4803 CHECK(r4->IsStringObject());
4804 CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
4805 Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
4806 CHECK(r5->IsBooleanObject());
4807 CHECK(r5.As<v8::BooleanObject>()->ValueOf());
4809 Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
4810 CHECK(r6->IsUndefined());
4811 Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
4812 CHECK(r7->IsNull());
4813 Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
4814 CHECK(r8->StrictEquals(v8_num(42)));
4815 Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
4816 CHECK(r9->StrictEquals(v8_str("hello")));
4817 Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
4818 CHECK(r10->StrictEquals(v8::True(isolate)));
4822 THREADED_TEST(ConstructCall) {
4823 LocalContext context;
4824 v8::Isolate* isolate = context->GetIsolate();
4825 v8::HandleScope scope(isolate);
4829 " for (var i = 0; i < arguments.length; i++) {"
4830 " result.push(arguments[i]);"
4834 Local<Function> Foo =
4835 Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
4837 v8::Handle<Value>* args0 = NULL;
4838 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0));
4839 CHECK_EQ(0, a0->Length());
4841 v8::Handle<Value> args1[] = { v8_num(1.1) };
4842 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1));
4843 CHECK_EQ(1, a1->Length());
4844 CHECK_EQ(1.1, a1->Get(v8::Integer::New(isolate, 0))->NumberValue());
4846 v8::Handle<Value> args2[] = { v8_num(2.2),
4848 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2));
4849 CHECK_EQ(2, a2->Length());
4850 CHECK_EQ(2.2, a2->Get(v8::Integer::New(isolate, 0))->NumberValue());
4851 CHECK_EQ(3.3, a2->Get(v8::Integer::New(isolate, 1))->NumberValue());
4853 v8::Handle<Value> args3[] = { v8_num(4.4),
4856 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3));
4857 CHECK_EQ(3, a3->Length());
4858 CHECK_EQ(4.4, a3->Get(v8::Integer::New(isolate, 0))->NumberValue());
4859 CHECK_EQ(5.5, a3->Get(v8::Integer::New(isolate, 1))->NumberValue());
4860 CHECK_EQ(6.6, a3->Get(v8::Integer::New(isolate, 2))->NumberValue());
4862 v8::Handle<Value> args4[] = { v8_num(7.7),
4866 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4));
4867 CHECK_EQ(4, a4->Length());
4868 CHECK_EQ(7.7, a4->Get(v8::Integer::New(isolate, 0))->NumberValue());
4869 CHECK_EQ(8.8, a4->Get(v8::Integer::New(isolate, 1))->NumberValue());
4870 CHECK_EQ(9.9, a4->Get(v8::Integer::New(isolate, 2))->NumberValue());
4871 CHECK_EQ(10.11, a4->Get(v8::Integer::New(isolate, 3))->NumberValue());
4875 static void CheckUncle(v8::TryCatch* try_catch) {
4876 CHECK(try_catch->HasCaught());
4877 String::Utf8Value str_value(try_catch->Exception());
4878 CHECK_EQ(*str_value, "uncle?");
4883 THREADED_TEST(ConversionNumber) {
4885 v8::HandleScope scope(env->GetIsolate());
4886 // Very large number.
4887 CompileRun("var obj = Math.pow(2,32) * 1237;");
4888 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4889 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
4890 CHECK_EQ(0, obj->ToInt32()->Value());
4891 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned.
4893 CompileRun("var obj = -1234567890123;");
4894 obj = env->Global()->Get(v8_str("obj"));
4895 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
4896 CHECK_EQ(-1912276171, obj->ToInt32()->Value());
4897 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT
4898 // Small positive integer.
4899 CompileRun("var obj = 42;");
4900 obj = env->Global()->Get(v8_str("obj"));
4901 CHECK_EQ(42.0, obj->ToNumber()->Value());
4902 CHECK_EQ(42, obj->ToInt32()->Value());
4903 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4904 // Negative integer.
4905 CompileRun("var obj = -37;");
4906 obj = env->Global()->Get(v8_str("obj"));
4907 CHECK_EQ(-37.0, obj->ToNumber()->Value());
4908 CHECK_EQ(-37, obj->ToInt32()->Value());
4909 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT
4910 // Positive non-int32 integer.
4911 CompileRun("var obj = 0x81234567;");
4912 obj = env->Global()->Get(v8_str("obj"));
4913 CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
4914 CHECK_EQ(-2128394905, obj->ToInt32()->Value());
4915 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT
4917 CompileRun("var obj = 42.3;");
4918 obj = env->Global()->Get(v8_str("obj"));
4919 CHECK_EQ(42.3, obj->ToNumber()->Value());
4920 CHECK_EQ(42, obj->ToInt32()->Value());
4921 CHECK(42u == obj->ToUint32()->Value()); // NOLINT
4922 // Large negative fraction.
4923 CompileRun("var obj = -5726623061.75;");
4924 obj = env->Global()->Get(v8_str("obj"));
4925 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
4926 CHECK_EQ(-1431655765, obj->ToInt32()->Value());
4927 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT
4931 THREADED_TEST(isNumberType) {
4933 v8::HandleScope scope(env->GetIsolate());
4934 // Very large number.
4935 CompileRun("var obj = Math.pow(2,32) * 1237;");
4936 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4937 CHECK(!obj->IsInt32());
4938 CHECK(!obj->IsUint32());
4939 // Large negative number.
4940 CompileRun("var obj = -1234567890123;");
4941 obj = env->Global()->Get(v8_str("obj"));
4942 CHECK(!obj->IsInt32());
4943 CHECK(!obj->IsUint32());
4944 // Small positive integer.
4945 CompileRun("var obj = 42;");
4946 obj = env->Global()->Get(v8_str("obj"));
4947 CHECK(obj->IsInt32());
4948 CHECK(obj->IsUint32());
4949 // Negative integer.
4950 CompileRun("var obj = -37;");
4951 obj = env->Global()->Get(v8_str("obj"));
4952 CHECK(obj->IsInt32());
4953 CHECK(!obj->IsUint32());
4954 // Positive non-int32 integer.
4955 CompileRun("var obj = 0x81234567;");
4956 obj = env->Global()->Get(v8_str("obj"));
4957 CHECK(!obj->IsInt32());
4958 CHECK(obj->IsUint32());
4960 CompileRun("var obj = 42.3;");
4961 obj = env->Global()->Get(v8_str("obj"));
4962 CHECK(!obj->IsInt32());
4963 CHECK(!obj->IsUint32());
4964 // Large negative fraction.
4965 CompileRun("var obj = -5726623061.75;");
4966 obj = env->Global()->Get(v8_str("obj"));
4967 CHECK(!obj->IsInt32());
4968 CHECK(!obj->IsUint32());
4970 CompileRun("var obj = 0.0;");
4971 obj = env->Global()->Get(v8_str("obj"));
4972 CHECK(obj->IsInt32());
4973 CHECK(obj->IsUint32());
4975 CompileRun("var obj = -0.0;");
4976 obj = env->Global()->Get(v8_str("obj"));
4977 CHECK(!obj->IsInt32());
4978 CHECK(!obj->IsUint32());
4982 THREADED_TEST(ConversionException) {
4984 v8::Isolate* isolate = env->GetIsolate();
4985 v8::HandleScope scope(isolate);
4987 "function TestClass() { };"
4988 "TestClass.prototype.toString = function () { throw 'uncle?'; };"
4989 "var obj = new TestClass();");
4990 Local<Value> obj = env->Global()->Get(v8_str("obj"));
4992 v8::TryCatch try_catch;
4994 Local<Value> to_string_result = obj->ToString();
4995 CHECK(to_string_result.IsEmpty());
4996 CheckUncle(&try_catch);
4998 Local<Value> to_number_result = obj->ToNumber();
4999 CHECK(to_number_result.IsEmpty());
5000 CheckUncle(&try_catch);
5002 Local<Value> to_integer_result = obj->ToInteger();
5003 CHECK(to_integer_result.IsEmpty());
5004 CheckUncle(&try_catch);
5006 Local<Value> to_uint32_result = obj->ToUint32();
5007 CHECK(to_uint32_result.IsEmpty());
5008 CheckUncle(&try_catch);
5010 Local<Value> to_int32_result = obj->ToInt32();
5011 CHECK(to_int32_result.IsEmpty());
5012 CheckUncle(&try_catch);
5014 Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
5015 CHECK(to_object_result.IsEmpty());
5016 CHECK(try_catch.HasCaught());
5019 int32_t int32_value = obj->Int32Value();
5020 CHECK_EQ(0, int32_value);
5021 CheckUncle(&try_catch);
5023 uint32_t uint32_value = obj->Uint32Value();
5024 CHECK_EQ(0, uint32_value);
5025 CheckUncle(&try_catch);
5027 double number_value = obj->NumberValue();
5028 CHECK_NE(0, std::isnan(number_value));
5029 CheckUncle(&try_catch);
5031 int64_t integer_value = obj->IntegerValue();
5032 CHECK_EQ(0.0, static_cast<double>(integer_value));
5033 CheckUncle(&try_catch);
5037 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) {
5038 ApiTestFuzzer::Fuzz();
5039 args.GetIsolate()->ThrowException(v8_str("konto"));
5043 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) {
5044 if (args.Length() < 1) {
5045 args.GetReturnValue().Set(false);
5048 v8::HandleScope scope(args.GetIsolate());
5049 v8::TryCatch try_catch;
5050 Local<Value> result = CompileRun(args[0]->ToString());
5051 CHECK(!try_catch.HasCaught() || result.IsEmpty());
5052 args.GetReturnValue().Set(try_catch.HasCaught());
5056 THREADED_TEST(APICatch) {
5057 v8::Isolate* isolate = CcTest::isolate();
5058 v8::HandleScope scope(isolate);
5059 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5060 templ->Set(v8_str("ThrowFromC"),
5061 v8::FunctionTemplate::New(isolate, ThrowFromC));
5062 LocalContext context(0, templ);
5064 "var thrown = false;"
5070 Local<Value> thrown = context->Global()->Get(v8_str("thrown"));
5071 CHECK(thrown->BooleanValue());
5075 THREADED_TEST(APIThrowTryCatch) {
5076 v8::Isolate* isolate = CcTest::isolate();
5077 v8::HandleScope scope(isolate);
5078 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5079 templ->Set(v8_str("ThrowFromC"),
5080 v8::FunctionTemplate::New(isolate, ThrowFromC));
5081 LocalContext context(0, templ);
5082 v8::TryCatch try_catch;
5083 CompileRun("ThrowFromC();");
5084 CHECK(try_catch.HasCaught());
5088 // Test that a try-finally block doesn't shadow a try-catch block
5089 // when setting up an external handler.
5091 // BUG(271): Some of the exception propagation does not work on the
5092 // ARM simulator because the simulator separates the C++ stack and the
5093 // JS stack. This test therefore fails on the simulator. The test is
5094 // not threaded to allow the threading tests to run on the simulator.
5095 TEST(TryCatchInTryFinally) {
5096 v8::Isolate* isolate = CcTest::isolate();
5097 v8::HandleScope scope(isolate);
5098 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5099 templ->Set(v8_str("CCatcher"),
5100 v8::FunctionTemplate::New(isolate, CCatcher));
5101 LocalContext context(0, templ);
5102 Local<Value> result = CompileRun("try {"
5104 " CCatcher('throw 7;');"
5109 CHECK(result->IsTrue());
5113 static void check_reference_error_message(
5114 v8::Handle<v8::Message> message,
5115 v8::Handle<v8::Value> data) {
5116 const char* reference_error = "Uncaught ReferenceError: asdf is not defined";
5117 CHECK(message->Get()->Equals(v8_str(reference_error)));
5121 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) {
5122 ApiTestFuzzer::Fuzz();
5127 // Test that overwritten methods are not invoked on uncaught exception
5128 // formatting. However, they are invoked when performing normal error
5129 // string conversions.
5130 TEST(APIThrowMessageOverwrittenToString) {
5131 v8::Isolate* isolate = CcTest::isolate();
5132 v8::HandleScope scope(isolate);
5133 v8::V8::AddMessageListener(check_reference_error_message);
5134 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5135 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(isolate, Fail));
5136 LocalContext context(NULL, templ);
5137 CompileRun("asdf;");
5138 CompileRun("var limit = {};"
5139 "limit.valueOf = fail;"
5140 "Error.stackTraceLimit = limit;");
5142 CompileRun("Array.prototype.pop = fail;");
5143 CompileRun("Object.prototype.hasOwnProperty = fail;");
5144 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }");
5145 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }");
5146 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }");
5147 CompileRun("ReferenceError.prototype.toString ="
5148 " function() { return 'Whoops' }");
5149 CompileRun("asdf;");
5150 CompileRun("ReferenceError.prototype.constructor.name = void 0;");
5151 CompileRun("asdf;");
5152 CompileRun("ReferenceError.prototype.constructor = void 0;");
5153 CompileRun("asdf;");
5154 CompileRun("ReferenceError.prototype.__proto__ = new Object();");
5155 CompileRun("asdf;");
5156 CompileRun("ReferenceError.prototype = new Object();");
5157 CompileRun("asdf;");
5158 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }");
5159 CHECK(string->Equals(v8_str("Whoops")));
5160 CompileRun("ReferenceError.prototype.constructor = new Object();"
5161 "ReferenceError.prototype.constructor.name = 1;"
5162 "Number.prototype.toString = function() { return 'Whoops'; };"
5163 "ReferenceError.prototype.toString = Object.prototype.toString;");
5164 CompileRun("asdf;");
5165 v8::V8::RemoveMessageListeners(check_reference_error_message);
5169 static void check_custom_error_tostring(
5170 v8::Handle<v8::Message> message,
5171 v8::Handle<v8::Value> data) {
5172 const char* uncaught_error = "Uncaught MyError toString";
5173 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5177 TEST(CustomErrorToString) {
5178 LocalContext context;
5179 v8::HandleScope scope(context->GetIsolate());
5180 v8::V8::AddMessageListener(check_custom_error_tostring);
5182 "function MyError(name, message) { "
5183 " this.name = name; "
5184 " this.message = message; "
5186 "MyError.prototype = Object.create(Error.prototype); "
5187 "MyError.prototype.toString = function() { "
5188 " return 'MyError toString'; "
5190 "throw new MyError('my name', 'my message'); ");
5191 v8::V8::RemoveMessageListeners(check_custom_error_tostring);
5195 static void check_custom_error_message(
5196 v8::Handle<v8::Message> message,
5197 v8::Handle<v8::Value> data) {
5198 const char* uncaught_error = "Uncaught MyError: my message";
5199 printf("%s\n", *v8::String::Utf8Value(message->Get()));
5200 CHECK(message->Get()->Equals(v8_str(uncaught_error)));
5204 TEST(CustomErrorMessage) {
5205 LocalContext context;
5206 v8::HandleScope scope(context->GetIsolate());
5207 v8::V8::AddMessageListener(check_custom_error_message);
5211 "function MyError(msg) { "
5212 " this.name = 'MyError'; "
5213 " this.message = msg; "
5215 "MyError.prototype = new Error(); "
5216 "throw new MyError('my message'); ");
5220 "function MyError(msg) { "
5221 " this.name = 'MyError'; "
5222 " this.message = msg; "
5224 "inherits = function(childCtor, parentCtor) { "
5225 " function tempCtor() {}; "
5226 " tempCtor.prototype = parentCtor.prototype; "
5227 " childCtor.superClass_ = parentCtor.prototype; "
5228 " childCtor.prototype = new tempCtor(); "
5229 " childCtor.prototype.constructor = childCtor; "
5231 "inherits(MyError, Error); "
5232 "throw new MyError('my message'); ");
5236 "function MyError(msg) { "
5237 " this.name = 'MyError'; "
5238 " this.message = msg; "
5240 "MyError.prototype = Object.create(Error.prototype); "
5241 "throw new MyError('my message'); ");
5243 v8::V8::RemoveMessageListeners(check_custom_error_message);
5247 static void receive_message(v8::Handle<v8::Message> message,
5248 v8::Handle<v8::Value> data) {
5250 message_received = true;
5254 TEST(APIThrowMessage) {
5255 message_received = false;
5256 v8::Isolate* isolate = CcTest::isolate();
5257 v8::HandleScope scope(isolate);
5258 v8::V8::AddMessageListener(receive_message);
5259 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5260 templ->Set(v8_str("ThrowFromC"),
5261 v8::FunctionTemplate::New(isolate, ThrowFromC));
5262 LocalContext context(0, templ);
5263 CompileRun("ThrowFromC();");
5264 CHECK(message_received);
5265 v8::V8::RemoveMessageListeners(receive_message);
5269 TEST(APIThrowMessageAndVerboseTryCatch) {
5270 message_received = false;
5271 v8::Isolate* isolate = CcTest::isolate();
5272 v8::HandleScope scope(isolate);
5273 v8::V8::AddMessageListener(receive_message);
5274 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5275 templ->Set(v8_str("ThrowFromC"),
5276 v8::FunctionTemplate::New(isolate, ThrowFromC));
5277 LocalContext context(0, templ);
5278 v8::TryCatch try_catch;
5279 try_catch.SetVerbose(true);
5280 Local<Value> result = CompileRun("ThrowFromC();");
5281 CHECK(try_catch.HasCaught());
5282 CHECK(result.IsEmpty());
5283 CHECK(message_received);
5284 v8::V8::RemoveMessageListeners(receive_message);
5288 TEST(APIStackOverflowAndVerboseTryCatch) {
5289 message_received = false;
5290 LocalContext context;
5291 v8::HandleScope scope(context->GetIsolate());
5292 v8::V8::AddMessageListener(receive_message);
5293 v8::TryCatch try_catch;
5294 try_catch.SetVerbose(true);
5295 Local<Value> result = CompileRun("function foo() { foo(); } foo();");
5296 CHECK(try_catch.HasCaught());
5297 CHECK(result.IsEmpty());
5298 CHECK(message_received);
5299 v8::V8::RemoveMessageListeners(receive_message);
5303 THREADED_TEST(ExternalScriptException) {
5304 v8::Isolate* isolate = CcTest::isolate();
5305 v8::HandleScope scope(isolate);
5306 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5307 templ->Set(v8_str("ThrowFromC"),
5308 v8::FunctionTemplate::New(isolate, ThrowFromC));
5309 LocalContext context(0, templ);
5311 v8::TryCatch try_catch;
5312 Local<Value> result = CompileRun("ThrowFromC(); throw 'panama';");
5313 CHECK(result.IsEmpty());
5314 CHECK(try_catch.HasCaught());
5315 String::Utf8Value exception_value(try_catch.Exception());
5316 CHECK_EQ("konto", *exception_value);
5321 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) {
5322 ApiTestFuzzer::Fuzz();
5323 CHECK_EQ(4, args.Length());
5324 int count = args[0]->Int32Value();
5325 int cInterval = args[2]->Int32Value();
5327 args.GetIsolate()->ThrowException(v8_str("FromC"));
5330 Local<v8::Object> global =
5331 args.GetIsolate()->GetCurrentContext()->Global();
5332 Local<Value> fun = global->Get(v8_str("JSThrowCountDown"));
5333 v8::Handle<Value> argv[] = { v8_num(count - 1),
5337 if (count % cInterval == 0) {
5338 v8::TryCatch try_catch;
5339 Local<Value> result = fun.As<Function>()->Call(global, 4, argv);
5340 int expected = args[3]->Int32Value();
5341 if (try_catch.HasCaught()) {
5342 CHECK_EQ(expected, count);
5343 CHECK(result.IsEmpty());
5344 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
5346 CHECK_NE(expected, count);
5348 args.GetReturnValue().Set(result);
5351 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv));
5358 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) {
5359 ApiTestFuzzer::Fuzz();
5360 CHECK_EQ(3, args.Length());
5361 bool equality = args[0]->BooleanValue();
5362 int count = args[1]->Int32Value();
5363 int expected = args[2]->Int32Value();
5365 CHECK_EQ(count, expected);
5367 CHECK_NE(count, expected);
5372 THREADED_TEST(EvalInTryFinally) {
5373 LocalContext context;
5374 v8::HandleScope scope(context->GetIsolate());
5375 v8::TryCatch try_catch;
5376 CompileRun("(function() {"
5378 " eval('asldkf (*&^&*^');"
5383 CHECK(!try_catch.HasCaught());
5387 // This test works by making a stack of alternating JavaScript and C
5388 // activations. These activations set up exception handlers with regular
5389 // intervals, one interval for C activations and another for JavaScript
5390 // activations. When enough activations have been created an exception is
5391 // thrown and we check that the right activation catches the exception and that
5392 // no other activations do. The right activation is always the topmost one with
5393 // a handler, regardless of whether it is in JavaScript or C.
5395 // The notation used to describe a test case looks like this:
5397 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5399 // Each entry is an activation, either JS or C. The index is the count at that
5400 // level. Stars identify activations with exception handlers, the @ identifies
5401 // the exception handler that should catch the exception.
5403 // BUG(271): Some of the exception propagation does not work on the
5404 // ARM simulator because the simulator separates the C++ stack and the
5405 // JS stack. This test therefore fails on the simulator. The test is
5406 // not threaded to allow the threading tests to run on the simulator.
5407 TEST(ExceptionOrder) {
5408 v8::Isolate* isolate = CcTest::isolate();
5409 v8::HandleScope scope(isolate);
5410 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5411 templ->Set(v8_str("check"), v8::FunctionTemplate::New(isolate, JSCheck));
5412 templ->Set(v8_str("CThrowCountDown"),
5413 v8::FunctionTemplate::New(isolate, CThrowCountDown));
5414 LocalContext context(0, templ);
5416 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {"
5417 " if (count == 0) throw 'FromJS';"
5418 " if (count % jsInterval == 0) {"
5420 " var value = CThrowCountDown(count - 1,"
5424 " check(false, count, expected);"
5427 " check(true, count, expected);"
5430 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);"
5433 Local<Function> fun =
5434 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown")));
5437 // count jsInterval cInterval expected
5439 // *JS[4] *C[3] @JS[2] C[1] JS[0]
5440 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) };
5441 fun->Call(fun, argc, a0);
5443 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0]
5444 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) };
5445 fun->Call(fun, argc, a1);
5447 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0]
5448 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) };
5449 fun->Call(fun, argc, a2);
5451 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0]
5452 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) };
5453 fun->Call(fun, argc, a3);
5455 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0]
5456 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) };
5457 fun->Call(fun, argc, a4);
5459 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0]
5460 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) };
5461 fun->Call(fun, argc, a5);
5465 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) {
5466 ApiTestFuzzer::Fuzz();
5467 CHECK_EQ(1, args.Length());
5468 args.GetIsolate()->ThrowException(args[0]);
5472 THREADED_TEST(ThrowValues) {
5473 v8::Isolate* isolate = CcTest::isolate();
5474 v8::HandleScope scope(isolate);
5475 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5476 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(isolate, ThrowValue));
5477 LocalContext context(0, templ);
5478 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
5479 "function Run(obj) {"
5485 " return 'no exception';"
5487 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];"));
5488 CHECK_EQ(5, result->Length());
5489 CHECK(result->Get(v8::Integer::New(isolate, 0))->IsString());
5490 CHECK(result->Get(v8::Integer::New(isolate, 1))->IsNumber());
5491 CHECK_EQ(1, result->Get(v8::Integer::New(isolate, 1))->Int32Value());
5492 CHECK(result->Get(v8::Integer::New(isolate, 2))->IsNumber());
5493 CHECK_EQ(0, result->Get(v8::Integer::New(isolate, 2))->Int32Value());
5494 CHECK(result->Get(v8::Integer::New(isolate, 3))->IsNull());
5495 CHECK(result->Get(v8::Integer::New(isolate, 4))->IsUndefined());
5499 THREADED_TEST(CatchZero) {
5500 LocalContext context;
5501 v8::HandleScope scope(context->GetIsolate());
5502 v8::TryCatch try_catch;
5503 CHECK(!try_catch.HasCaught());
5504 CompileRun("throw 10");
5505 CHECK(try_catch.HasCaught());
5506 CHECK_EQ(10, try_catch.Exception()->Int32Value());
5508 CHECK(!try_catch.HasCaught());
5509 CompileRun("throw 0");
5510 CHECK(try_catch.HasCaught());
5511 CHECK_EQ(0, try_catch.Exception()->Int32Value());
5515 THREADED_TEST(CatchExceptionFromWith) {
5516 LocalContext context;
5517 v8::HandleScope scope(context->GetIsolate());
5518 v8::TryCatch try_catch;
5519 CHECK(!try_catch.HasCaught());
5520 CompileRun("var o = {}; with (o) { throw 42; }");
5521 CHECK(try_catch.HasCaught());
5525 THREADED_TEST(TryCatchAndFinallyHidingException) {
5526 LocalContext context;
5527 v8::HandleScope scope(context->GetIsolate());
5528 v8::TryCatch try_catch;
5529 CHECK(!try_catch.HasCaught());
5530 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };");
5531 CompileRun("f({toString: function() { throw 42; }});");
5532 CHECK(!try_catch.HasCaught());
5536 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
5537 v8::TryCatch try_catch;
5541 THREADED_TEST(TryCatchAndFinally) {
5542 LocalContext context;
5543 v8::Isolate* isolate = context->GetIsolate();
5544 v8::HandleScope scope(isolate);
5545 context->Global()->Set(
5546 v8_str("native_with_try_catch"),
5547 v8::FunctionTemplate::New(isolate, WithTryCatch)->GetFunction());
5548 v8::TryCatch try_catch;
5549 CHECK(!try_catch.HasCaught());
5552 " throw new Error('a');\n"
5554 " native_with_try_catch();\n"
5556 CHECK(try_catch.HasCaught());
5560 static void TryCatchNested1Helper(int depth) {
5562 v8::TryCatch try_catch;
5563 try_catch.SetVerbose(true);
5564 TryCatchNested1Helper(depth - 1);
5565 CHECK(try_catch.HasCaught());
5566 try_catch.ReThrow();
5568 CcTest::isolate()->ThrowException(v8_str("E1"));
5573 static void TryCatchNested2Helper(int depth) {
5575 v8::TryCatch try_catch;
5576 try_catch.SetVerbose(true);
5577 TryCatchNested2Helper(depth - 1);
5578 CHECK(try_catch.HasCaught());
5579 try_catch.ReThrow();
5581 CompileRun("throw 'E2';");
5586 TEST(TryCatchNested) {
5587 v8::V8::Initialize();
5588 LocalContext context;
5589 v8::HandleScope scope(context->GetIsolate());
5592 // Test nested try-catch with a native throw in the end.
5593 v8::TryCatch try_catch;
5594 TryCatchNested1Helper(5);
5595 CHECK(try_catch.HasCaught());
5596 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E1"));
5600 // Test nested try-catch with a JavaScript throw in the end.
5601 v8::TryCatch try_catch;
5602 TryCatchNested2Helper(5);
5603 CHECK(try_catch.HasCaught());
5604 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "E2"));
5609 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) {
5610 CHECK(try_catch->HasCaught());
5611 Handle<Message> message = try_catch->Message();
5612 Handle<Value> resource = message->GetScriptOrigin().ResourceName();
5613 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner"));
5614 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()),
5615 "Uncaught Error: a"));
5616 CHECK_EQ(1, message->GetLineNumber());
5617 CHECK_EQ(6, message->GetStartColumn());
5621 void TryCatchMixedNestingHelper(
5622 const v8::FunctionCallbackInfo<v8::Value>& args) {
5623 ApiTestFuzzer::Fuzz();
5624 v8::TryCatch try_catch;
5625 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0);
5626 CHECK(try_catch.HasCaught());
5627 TryCatchMixedNestingCheck(&try_catch);
5628 try_catch.ReThrow();
5632 // This test ensures that an outer TryCatch in the following situation:
5633 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError
5634 // does not clobber the Message object generated for the inner TryCatch.
5635 // This exercises the ability of TryCatch.ReThrow() to restore the
5636 // inner pending Message before throwing the exception again.
5637 TEST(TryCatchMixedNesting) {
5638 v8::Isolate* isolate = CcTest::isolate();
5639 v8::HandleScope scope(isolate);
5640 v8::V8::Initialize();
5641 v8::TryCatch try_catch;
5642 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5643 templ->Set(v8_str("TryCatchMixedNestingHelper"),
5644 v8::FunctionTemplate::New(isolate, TryCatchMixedNestingHelper));
5645 LocalContext context(0, templ);
5646 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1);
5647 TryCatchMixedNestingCheck(&try_catch);
5651 void TryCatchNativeHelper(const v8::FunctionCallbackInfo<v8::Value>& args) {
5652 ApiTestFuzzer::Fuzz();
5653 v8::TryCatch try_catch;
5654 args.GetIsolate()->ThrowException(v8_str("boom"));
5655 CHECK(try_catch.HasCaught());
5659 TEST(TryCatchNative) {
5660 v8::Isolate* isolate = CcTest::isolate();
5661 v8::HandleScope scope(isolate);
5662 v8::V8::Initialize();
5663 v8::TryCatch try_catch;
5664 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5665 templ->Set(v8_str("TryCatchNativeHelper"),
5666 v8::FunctionTemplate::New(isolate, TryCatchNativeHelper));
5667 LocalContext context(0, templ);
5668 CompileRun("TryCatchNativeHelper();");
5669 CHECK(!try_catch.HasCaught());
5673 void TryCatchNativeResetHelper(
5674 const v8::FunctionCallbackInfo<v8::Value>& args) {
5675 ApiTestFuzzer::Fuzz();
5676 v8::TryCatch try_catch;
5677 args.GetIsolate()->ThrowException(v8_str("boom"));
5678 CHECK(try_catch.HasCaught());
5680 CHECK(!try_catch.HasCaught());
5684 TEST(TryCatchNativeReset) {
5685 v8::Isolate* isolate = CcTest::isolate();
5686 v8::HandleScope scope(isolate);
5687 v8::V8::Initialize();
5688 v8::TryCatch try_catch;
5689 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5690 templ->Set(v8_str("TryCatchNativeResetHelper"),
5691 v8::FunctionTemplate::New(isolate, TryCatchNativeResetHelper));
5692 LocalContext context(0, templ);
5693 CompileRun("TryCatchNativeResetHelper();");
5694 CHECK(!try_catch.HasCaught());
5698 THREADED_TEST(Equality) {
5699 LocalContext context;
5700 v8::Isolate* isolate = context->GetIsolate();
5701 v8::HandleScope scope(context->GetIsolate());
5702 // Check that equality works at all before relying on CHECK_EQ
5703 CHECK(v8_str("a")->Equals(v8_str("a")));
5704 CHECK(!v8_str("a")->Equals(v8_str("b")));
5706 CHECK_EQ(v8_str("a"), v8_str("a"));
5707 CHECK_NE(v8_str("a"), v8_str("b"));
5708 CHECK_EQ(v8_num(1), v8_num(1));
5709 CHECK_EQ(v8_num(1.00), v8_num(1));
5710 CHECK_NE(v8_num(1), v8_num(2));
5712 // Assume String is not internalized.
5713 CHECK(v8_str("a")->StrictEquals(v8_str("a")));
5714 CHECK(!v8_str("a")->StrictEquals(v8_str("b")));
5715 CHECK(!v8_str("5")->StrictEquals(v8_num(5)));
5716 CHECK(v8_num(1)->StrictEquals(v8_num(1)));
5717 CHECK(!v8_num(1)->StrictEquals(v8_num(2)));
5718 CHECK(v8_num(0.0)->StrictEquals(v8_num(-0.0)));
5719 Local<Value> not_a_number = v8_num(v8::base::OS::nan_value());
5720 CHECK(!not_a_number->StrictEquals(not_a_number));
5721 CHECK(v8::False(isolate)->StrictEquals(v8::False(isolate)));
5722 CHECK(!v8::False(isolate)->StrictEquals(v8::Undefined(isolate)));
5724 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
5725 v8::Persistent<v8::Object> alias(isolate, obj);
5726 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj));
5729 CHECK(v8_str("a")->SameValue(v8_str("a")));
5730 CHECK(!v8_str("a")->SameValue(v8_str("b")));
5731 CHECK(!v8_str("5")->SameValue(v8_num(5)));
5732 CHECK(v8_num(1)->SameValue(v8_num(1)));
5733 CHECK(!v8_num(1)->SameValue(v8_num(2)));
5734 CHECK(!v8_num(0.0)->SameValue(v8_num(-0.0)));
5735 CHECK(not_a_number->SameValue(not_a_number));
5736 CHECK(v8::False(isolate)->SameValue(v8::False(isolate)));
5737 CHECK(!v8::False(isolate)->SameValue(v8::Undefined(isolate)));
5741 THREADED_TEST(MultiRun) {
5742 LocalContext context;
5743 v8::HandleScope scope(context->GetIsolate());
5744 Local<Script> script = v8_compile("x");
5745 for (int i = 0; i < 10; i++)
5750 static void GetXValue(Local<String> name,
5751 const v8::PropertyCallbackInfo<v8::Value>& info) {
5752 ApiTestFuzzer::Fuzz();
5753 CHECK_EQ(info.Data(), v8_str("donut"));
5754 CHECK_EQ(name, v8_str("x"));
5755 info.GetReturnValue().Set(name);
5759 THREADED_TEST(SimplePropertyRead) {
5760 LocalContext context;
5761 v8::Isolate* isolate = context->GetIsolate();
5762 v8::HandleScope scope(isolate);
5763 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5764 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5765 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5766 Local<Script> script = v8_compile("obj.x");
5767 for (int i = 0; i < 10; i++) {
5768 Local<Value> result = script->Run();
5769 CHECK_EQ(result, v8_str("x"));
5774 THREADED_TEST(DefinePropertyOnAPIAccessor) {
5775 LocalContext context;
5776 v8::Isolate* isolate = context->GetIsolate();
5777 v8::HandleScope scope(isolate);
5778 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5779 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5780 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5782 // Uses getOwnPropertyDescriptor to check the configurable status
5783 Local<Script> script_desc = v8_compile(
5784 "var prop = Object.getOwnPropertyDescriptor( "
5786 "prop.configurable;");
5787 Local<Value> result = script_desc->Run();
5788 CHECK_EQ(result->BooleanValue(), true);
5790 // Redefine get - but still configurable
5791 Local<Script> script_define = v8_compile(
5792 "var desc = { get: function(){return 42; },"
5793 " configurable: true };"
5794 "Object.defineProperty(obj, 'x', desc);"
5796 result = script_define->Run();
5797 CHECK_EQ(result, v8_num(42));
5799 // Check that the accessor is still configurable
5800 result = script_desc->Run();
5801 CHECK_EQ(result->BooleanValue(), true);
5803 // Redefine to a non-configurable
5804 script_define = v8_compile(
5805 "var desc = { get: function(){return 43; },"
5806 " configurable: false };"
5807 "Object.defineProperty(obj, 'x', desc);"
5809 result = script_define->Run();
5810 CHECK_EQ(result, v8_num(43));
5811 result = script_desc->Run();
5812 CHECK_EQ(result->BooleanValue(), false);
5814 // Make sure that it is not possible to redefine again
5815 v8::TryCatch try_catch;
5816 result = script_define->Run();
5817 CHECK(try_catch.HasCaught());
5818 String::Utf8Value exception_value(try_catch.Exception());
5819 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5823 THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
5824 v8::Isolate* isolate = CcTest::isolate();
5825 v8::HandleScope scope(isolate);
5826 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5827 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
5828 LocalContext context;
5829 context->Global()->Set(v8_str("obj"), templ->NewInstance());
5831 Local<Script> script_desc = v8_compile(
5833 "Object.getOwnPropertyDescriptor( "
5835 "prop.configurable;");
5836 Local<Value> result = script_desc->Run();
5837 CHECK_EQ(result->BooleanValue(), true);
5839 Local<Script> script_define = v8_compile(
5840 "var desc = {get: function(){return 42; },"
5841 " configurable: true };"
5842 "Object.defineProperty(obj, 'x', desc);"
5844 result = script_define->Run();
5845 CHECK_EQ(result, v8_num(42));
5848 result = script_desc->Run();
5849 CHECK_EQ(result->BooleanValue(), true);
5852 script_define = v8_compile(
5853 "var desc = {get: function(){return 43; },"
5854 " configurable: false };"
5855 "Object.defineProperty(obj, 'x', desc);"
5857 result = script_define->Run();
5858 CHECK_EQ(result, v8_num(43));
5859 result = script_desc->Run();
5861 CHECK_EQ(result->BooleanValue(), false);
5863 v8::TryCatch try_catch;
5864 result = script_define->Run();
5865 CHECK(try_catch.HasCaught());
5866 String::Utf8Value exception_value(try_catch.Exception());
5867 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5871 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context,
5873 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name)));
5877 THREADED_TEST(DefineAPIAccessorOnObject) {
5878 v8::Isolate* isolate = CcTest::isolate();
5879 v8::HandleScope scope(isolate);
5880 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5881 LocalContext context;
5883 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5884 CompileRun("var obj2 = {};");
5886 CHECK(CompileRun("obj1.x")->IsUndefined());
5887 CHECK(CompileRun("obj2.x")->IsUndefined());
5889 CHECK(GetGlobalProperty(&context, "obj1")->
5890 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5892 ExpectString("obj1.x", "x");
5893 CHECK(CompileRun("obj2.x")->IsUndefined());
5895 CHECK(GetGlobalProperty(&context, "obj2")->
5896 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5898 ExpectString("obj1.x", "x");
5899 ExpectString("obj2.x", "x");
5901 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5902 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5904 CompileRun("Object.defineProperty(obj1, 'x',"
5905 "{ get: function() { return 'y'; }, configurable: true })");
5907 ExpectString("obj1.x", "y");
5908 ExpectString("obj2.x", "x");
5910 CompileRun("Object.defineProperty(obj2, 'x',"
5911 "{ get: function() { return 'y'; }, configurable: true })");
5913 ExpectString("obj1.x", "y");
5914 ExpectString("obj2.x", "y");
5916 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5917 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5919 CHECK(GetGlobalProperty(&context, "obj1")->
5920 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5921 CHECK(GetGlobalProperty(&context, "obj2")->
5922 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5924 ExpectString("obj1.x", "x");
5925 ExpectString("obj2.x", "x");
5927 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5928 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5930 // Define getters/setters, but now make them not configurable.
5931 CompileRun("Object.defineProperty(obj1, 'x',"
5932 "{ get: function() { return 'z'; }, configurable: false })");
5933 CompileRun("Object.defineProperty(obj2, 'x',"
5934 "{ get: function() { return 'z'; }, configurable: false })");
5936 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5937 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5939 ExpectString("obj1.x", "z");
5940 ExpectString("obj2.x", "z");
5942 CHECK(!GetGlobalProperty(&context, "obj1")->
5943 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5944 CHECK(!GetGlobalProperty(&context, "obj2")->
5945 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5947 ExpectString("obj1.x", "z");
5948 ExpectString("obj2.x", "z");
5952 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) {
5953 v8::Isolate* isolate = CcTest::isolate();
5954 v8::HandleScope scope(isolate);
5955 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
5956 LocalContext context;
5958 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
5959 CompileRun("var obj2 = {};");
5961 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
5964 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5965 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
5968 v8_str("donut"), v8::DEFAULT, v8::DontDelete));
5970 ExpectString("obj1.x", "x");
5971 ExpectString("obj2.x", "x");
5973 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable");
5974 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable");
5976 CHECK(!GetGlobalProperty(&context, "obj1")->
5977 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5978 CHECK(!GetGlobalProperty(&context, "obj2")->
5979 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")));
5982 v8::TryCatch try_catch;
5983 CompileRun("Object.defineProperty(obj1, 'x',"
5984 "{get: function() { return 'func'; }})");
5985 CHECK(try_catch.HasCaught());
5986 String::Utf8Value exception_value(try_catch.Exception());
5987 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
5990 v8::TryCatch try_catch;
5991 CompileRun("Object.defineProperty(obj2, 'x',"
5992 "{get: function() { return 'func'; }})");
5993 CHECK(try_catch.HasCaught());
5994 String::Utf8Value exception_value(try_catch.Exception());
5995 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x");
6000 static void Get239Value(Local<String> name,
6001 const v8::PropertyCallbackInfo<v8::Value>& info) {
6002 ApiTestFuzzer::Fuzz();
6003 CHECK_EQ(info.Data(), v8_str("donut"));
6004 CHECK_EQ(name, v8_str("239"));
6005 info.GetReturnValue().Set(name);
6009 THREADED_TEST(ElementAPIAccessor) {
6010 v8::Isolate* isolate = CcTest::isolate();
6011 v8::HandleScope scope(isolate);
6012 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6013 LocalContext context;
6015 context->Global()->Set(v8_str("obj1"), templ->NewInstance());
6016 CompileRun("var obj2 = {};");
6018 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor(
6022 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor(
6027 ExpectString("obj1[239]", "239");
6028 ExpectString("obj2[239]", "239");
6029 ExpectString("obj1['239']", "239");
6030 ExpectString("obj2['239']", "239");
6034 v8::Persistent<Value> xValue;
6037 static void SetXValue(Local<String> name,
6039 const v8::PropertyCallbackInfo<void>& info) {
6040 CHECK_EQ(value, v8_num(4));
6041 CHECK_EQ(info.Data(), v8_str("donut"));
6042 CHECK_EQ(name, v8_str("x"));
6043 CHECK(xValue.IsEmpty());
6044 xValue.Reset(info.GetIsolate(), value);
6048 THREADED_TEST(SimplePropertyWrite) {
6049 v8::Isolate* isolate = CcTest::isolate();
6050 v8::HandleScope scope(isolate);
6051 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6052 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut"));
6053 LocalContext context;
6054 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6055 Local<Script> script = v8_compile("obj.x = 4");
6056 for (int i = 0; i < 10; i++) {
6057 CHECK(xValue.IsEmpty());
6059 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6065 THREADED_TEST(SetterOnly) {
6066 v8::Isolate* isolate = CcTest::isolate();
6067 v8::HandleScope scope(isolate);
6068 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6069 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut"));
6070 LocalContext context;
6071 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6072 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6073 for (int i = 0; i < 10; i++) {
6074 CHECK(xValue.IsEmpty());
6076 CHECK_EQ(v8_num(4), Local<Value>::New(CcTest::isolate(), xValue));
6082 THREADED_TEST(NoAccessors) {
6083 v8::Isolate* isolate = CcTest::isolate();
6084 v8::HandleScope scope(isolate);
6085 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6086 templ->SetAccessor(v8_str("x"),
6087 static_cast<v8::AccessorGetterCallback>(NULL),
6090 LocalContext context;
6091 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6092 Local<Script> script = v8_compile("obj.x = 4; obj.x");
6093 for (int i = 0; i < 10; i++) {
6099 static void XPropertyGetter(Local<String> property,
6100 const v8::PropertyCallbackInfo<v8::Value>& info) {
6101 ApiTestFuzzer::Fuzz();
6102 CHECK(info.Data()->IsUndefined());
6103 info.GetReturnValue().Set(property);
6107 THREADED_TEST(NamedInterceptorPropertyRead) {
6108 v8::Isolate* isolate = CcTest::isolate();
6109 v8::HandleScope scope(isolate);
6110 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6111 templ->SetNamedPropertyHandler(XPropertyGetter);
6112 LocalContext context;
6113 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6114 Local<Script> script = v8_compile("obj.x");
6115 for (int i = 0; i < 10; i++) {
6116 Local<Value> result = script->Run();
6117 CHECK_EQ(result, v8_str("x"));
6122 THREADED_TEST(NamedInterceptorDictionaryIC) {
6123 v8::Isolate* isolate = CcTest::isolate();
6124 v8::HandleScope scope(isolate);
6125 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6126 templ->SetNamedPropertyHandler(XPropertyGetter);
6127 LocalContext context;
6128 // Create an object with a named interceptor.
6129 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
6130 Local<Script> script = v8_compile("interceptor_obj.x");
6131 for (int i = 0; i < 10; i++) {
6132 Local<Value> result = script->Run();
6133 CHECK_EQ(result, v8_str("x"));
6135 // Create a slow case object and a function accessing a property in
6136 // that slow case object (with dictionary probing in generated
6137 // code). Then force object with a named interceptor into slow-case,
6138 // pass it to the function, and check that the interceptor is called
6139 // instead of accessing the local property.
6140 Local<Value> result =
6141 CompileRun("function get_x(o) { return o.x; };"
6142 "var obj = { x : 42, y : 0 };"
6144 "for (var i = 0; i < 10; i++) get_x(obj);"
6145 "interceptor_obj.x = 42;"
6146 "interceptor_obj.y = 10;"
6147 "delete interceptor_obj.y;"
6148 "get_x(interceptor_obj)");
6149 CHECK_EQ(result, v8_str("x"));
6153 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) {
6154 v8::Isolate* isolate = CcTest::isolate();
6155 v8::HandleScope scope(isolate);
6156 v8::Local<Context> context1 = Context::New(isolate);
6159 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6160 templ->SetNamedPropertyHandler(XPropertyGetter);
6161 // Create an object with a named interceptor.
6162 v8::Local<v8::Object> object = templ->NewInstance();
6163 context1->Global()->Set(v8_str("interceptor_obj"), object);
6165 // Force the object into the slow case.
6166 CompileRun("interceptor_obj.y = 0;"
6167 "delete interceptor_obj.y;");
6171 // Introduce the object into a different context.
6172 // Repeat named loads to exercise ICs.
6173 LocalContext context2;
6174 context2->Global()->Set(v8_str("interceptor_obj"), object);
6175 Local<Value> result =
6176 CompileRun("function get_x(o) { return o.x; }"
6177 "interceptor_obj.x = 42;"
6178 "for (var i=0; i != 10; i++) {"
6179 " get_x(interceptor_obj);"
6181 "get_x(interceptor_obj)");
6182 // Check that the interceptor was actually invoked.
6183 CHECK_EQ(result, v8_str("x"));
6186 // Return to the original context and force some object to the slow case
6187 // to cause the NormalizedMapCache to verify.
6189 CompileRun("var obj = { x : 0 }; delete obj.x;");
6194 static void SetXOnPrototypeGetter(
6195 Local<String> property,
6196 const v8::PropertyCallbackInfo<v8::Value>& info) {
6197 // Set x on the prototype object and do not handle the get request.
6198 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
6199 proto.As<v8::Object>()->Set(v8_str("x"),
6200 v8::Integer::New(info.GetIsolate(), 23));
6204 // This is a regression test for http://crbug.com/20104. Map
6205 // transitions should not interfere with post interceptor lookup.
6206 THREADED_TEST(NamedInterceptorMapTransitionRead) {
6207 v8::Isolate* isolate = CcTest::isolate();
6208 v8::HandleScope scope(isolate);
6209 Local<v8::FunctionTemplate> function_template =
6210 v8::FunctionTemplate::New(isolate);
6211 Local<v8::ObjectTemplate> instance_template
6212 = function_template->InstanceTemplate();
6213 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
6214 LocalContext context;
6215 context->Global()->Set(v8_str("F"), function_template->GetFunction());
6216 // Create an instance of F and introduce a map transition for x.
6217 CompileRun("var o = new F(); o.x = 23;");
6218 // Create an instance of F and invoke the getter. The result should be 23.
6219 Local<Value> result = CompileRun("o = new F(); o.x");
6220 CHECK_EQ(result->Int32Value(), 23);
6224 static void IndexedPropertyGetter(
6226 const v8::PropertyCallbackInfo<v8::Value>& info) {
6227 ApiTestFuzzer::Fuzz();
6229 info.GetReturnValue().Set(v8_num(625));
6234 static void IndexedPropertySetter(
6237 const v8::PropertyCallbackInfo<v8::Value>& info) {
6238 ApiTestFuzzer::Fuzz();
6240 info.GetReturnValue().Set(value);
6245 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) {
6246 v8::Isolate* isolate = CcTest::isolate();
6247 v8::HandleScope scope(isolate);
6248 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6249 templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
6250 IndexedPropertySetter);
6251 LocalContext context;
6252 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6253 Local<Script> getter_script = v8_compile(
6254 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];");
6255 Local<Script> setter_script = v8_compile(
6256 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});"
6259 Local<Script> interceptor_setter_script = v8_compile(
6260 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});"
6262 "obj.foo;"); // This setter should not run, due to the interceptor.
6263 Local<Script> interceptor_getter_script = v8_compile(
6265 Local<Value> result = getter_script->Run();
6266 CHECK_EQ(v8_num(5), result);
6267 result = setter_script->Run();
6268 CHECK_EQ(v8_num(23), result);
6269 result = interceptor_setter_script->Run();
6270 CHECK_EQ(v8_num(23), result);
6271 result = interceptor_getter_script->Run();
6272 CHECK_EQ(v8_num(625), result);
6276 static void UnboxedDoubleIndexedPropertyGetter(
6278 const v8::PropertyCallbackInfo<v8::Value>& info) {
6279 ApiTestFuzzer::Fuzz();
6281 info.GetReturnValue().Set(v8_num(index));
6286 static void UnboxedDoubleIndexedPropertySetter(
6289 const v8::PropertyCallbackInfo<v8::Value>& info) {
6290 ApiTestFuzzer::Fuzz();
6292 info.GetReturnValue().Set(v8_num(index));
6297 void UnboxedDoubleIndexedPropertyEnumerator(
6298 const v8::PropertyCallbackInfo<v8::Array>& info) {
6299 // Force the list of returned keys to be stored in a FastDoubleArray.
6300 Local<Script> indexed_property_names_script = v8_compile(
6301 "keys = new Array(); keys[125000] = 1;"
6302 "for(i = 0; i < 80000; i++) { keys[i] = i; };"
6303 "keys.length = 25; keys;");
6304 Local<Value> result = indexed_property_names_script->Run();
6305 info.GetReturnValue().Set(Local<v8::Array>::Cast(result));
6309 // Make sure that the the interceptor code in the runtime properly handles
6310 // merging property name lists for double-array-backed arrays.
6311 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) {
6312 v8::Isolate* isolate = CcTest::isolate();
6313 v8::HandleScope scope(isolate);
6314 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6315 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
6316 UnboxedDoubleIndexedPropertySetter,
6319 UnboxedDoubleIndexedPropertyEnumerator);
6320 LocalContext context;
6321 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6322 // When obj is created, force it to be Stored in a FastDoubleArray.
6323 Local<Script> create_unboxed_double_script = v8_compile(
6324 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } "
6326 "for (x in obj) {key_count++;};"
6328 Local<Value> result = create_unboxed_double_script->Run();
6329 CHECK(result->ToObject()->HasRealIndexedProperty(2000));
6330 Local<Script> key_count_check = v8_compile("key_count;");
6331 result = key_count_check->Run();
6332 CHECK_EQ(v8_num(40013), result);
6336 void SloppyArgsIndexedPropertyEnumerator(
6337 const v8::PropertyCallbackInfo<v8::Array>& info) {
6338 // Force the list of returned keys to be stored in a Arguments object.
6339 Local<Script> indexed_property_names_script = v8_compile(
6341 " return arguments;"
6343 "keys = f(0, 1, 2, 3);"
6345 Local<Object> result =
6346 Local<Object>::Cast(indexed_property_names_script->Run());
6347 // Have to populate the handle manually, as it's not Cast-able.
6348 i::Handle<i::JSObject> o =
6349 v8::Utils::OpenHandle<Object, i::JSObject>(result);
6350 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o));
6351 info.GetReturnValue().Set(v8::Utils::ToLocal(array));
6355 static void SloppyIndexedPropertyGetter(
6357 const v8::PropertyCallbackInfo<v8::Value>& info) {
6358 ApiTestFuzzer::Fuzz();
6360 info.GetReturnValue().Set(v8_num(index));
6365 // Make sure that the the interceptor code in the runtime properly handles
6366 // merging property name lists for non-string arguments arrays.
6367 THREADED_TEST(IndexedInterceptorSloppyArgsWithIndexedAccessor) {
6368 v8::Isolate* isolate = CcTest::isolate();
6369 v8::HandleScope scope(isolate);
6370 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6371 templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
6375 SloppyArgsIndexedPropertyEnumerator);
6376 LocalContext context;
6377 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6378 Local<Script> create_args_script = v8_compile(
6379 "var key_count = 0;"
6380 "for (x in obj) {key_count++;} key_count;");
6381 Local<Value> result = create_args_script->Run();
6382 CHECK_EQ(v8_num(4), result);
6386 static void IdentityIndexedPropertyGetter(
6388 const v8::PropertyCallbackInfo<v8::Value>& info) {
6389 info.GetReturnValue().Set(index);
6393 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) {
6394 v8::Isolate* isolate = CcTest::isolate();
6395 v8::HandleScope scope(isolate);
6396 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6397 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6399 LocalContext context;
6400 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6402 // Check fast object case.
6403 const char* fast_case_code =
6404 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()";
6405 ExpectString(fast_case_code, "0");
6408 const char* slow_case_code =
6409 "obj.x = 1; delete obj.x;"
6410 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()";
6411 ExpectString(slow_case_code, "1");
6415 THREADED_TEST(IndexedInterceptorWithNoSetter) {
6416 v8::Isolate* isolate = CcTest::isolate();
6417 v8::HandleScope scope(isolate);
6418 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6419 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6421 LocalContext context;
6422 context->Global()->Set(v8_str("obj"), templ->NewInstance());
6427 " for (var i = 0; i < 100; i++) {"
6429 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;"
6435 ExpectString(code, "PASSED");
6439 THREADED_TEST(IndexedInterceptorWithAccessorCheck) {
6440 v8::Isolate* isolate = CcTest::isolate();
6441 v8::HandleScope scope(isolate);
6442 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6443 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6445 LocalContext context;
6446 Local<v8::Object> obj = templ->NewInstance();
6447 obj->TurnOnAccessCheck();
6448 context->Global()->Set(v8_str("obj"), obj);
6451 "var result = 'PASSED';"
6452 "for (var i = 0; i < 100; i++) {"
6455 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6462 ExpectString(code, "PASSED");
6466 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) {
6467 i::FLAG_allow_natives_syntax = true;
6468 v8::Isolate* isolate = CcTest::isolate();
6469 v8::HandleScope scope(isolate);
6470 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6471 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6473 LocalContext context;
6474 Local<v8::Object> obj = templ->NewInstance();
6475 context->Global()->Set(v8_str("obj"), obj);
6478 "var result = 'PASSED';"
6479 "for (var i = 0; i < 100; i++) {"
6480 " var expected = i;"
6482 " %EnableAccessChecks(obj);"
6487 " result = 'Should not have reached this!';"
6489 " } else if (v != expected) {"
6490 " result = 'Wrong value ' + v + ' at iteration ' + i;"
6498 " if (i == 5) %DisableAccessChecks(obj);"
6501 ExpectString(code, "PASSED");
6505 THREADED_TEST(IndexedInterceptorWithDifferentIndices) {
6506 v8::Isolate* isolate = CcTest::isolate();
6507 v8::HandleScope scope(isolate);
6508 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6509 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6511 LocalContext context;
6512 Local<v8::Object> obj = templ->NewInstance();
6513 context->Global()->Set(v8_str("obj"), obj);
6517 " for (var i = 0; i < 100; i++) {"
6519 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6525 ExpectString(code, "PASSED");
6529 THREADED_TEST(IndexedInterceptorWithNegativeIndices) {
6530 v8::Isolate* isolate = CcTest::isolate();
6531 v8::HandleScope scope(isolate);
6532 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6533 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6535 LocalContext context;
6536 Local<v8::Object> obj = templ->NewInstance();
6537 context->Global()->Set(v8_str("obj"), obj);
6541 " for (var i = 0; i < 100; i++) {"
6542 " var expected = i;"
6546 " expected = undefined;"
6549 " /* probe minimal Smi number on 32-bit platforms */"
6550 " key = -(1 << 30);"
6551 " expected = undefined;"
6554 " /* probe minimal Smi number on 64-bit platforms */"
6556 " expected = undefined;"
6558 " var v = obj[key];"
6559 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6565 ExpectString(code, "PASSED");
6569 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) {
6570 v8::Isolate* isolate = CcTest::isolate();
6571 v8::HandleScope scope(isolate);
6572 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6573 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6575 LocalContext context;
6576 Local<v8::Object> obj = templ->NewInstance();
6577 context->Global()->Set(v8_str("obj"), obj);
6581 " for (var i = 0; i < 100; i++) {"
6582 " var expected = i;"
6586 " expected = undefined;"
6588 " var v = obj[key];"
6589 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6595 ExpectString(code, "PASSED");
6599 THREADED_TEST(IndexedInterceptorGoingMegamorphic) {
6600 v8::Isolate* isolate = CcTest::isolate();
6601 v8::HandleScope scope(isolate);
6602 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6603 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6605 LocalContext context;
6606 Local<v8::Object> obj = templ->NewInstance();
6607 context->Global()->Set(v8_str("obj"), obj);
6610 "var original = obj;"
6612 " for (var i = 0; i < 100; i++) {"
6613 " var expected = i;"
6615 " obj = {50: 'foobar'};"
6616 " expected = 'foobar';"
6619 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6620 " if (i == 50) obj = original;"
6626 ExpectString(code, "PASSED");
6630 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) {
6631 v8::Isolate* isolate = CcTest::isolate();
6632 v8::HandleScope scope(isolate);
6633 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6634 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6636 LocalContext context;
6637 Local<v8::Object> obj = templ->NewInstance();
6638 context->Global()->Set(v8_str("obj"), obj);
6641 "var original = obj;"
6643 " for (var i = 0; i < 100; i++) {"
6644 " var expected = i;"
6647 " expected = undefined;"
6650 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;"
6651 " if (i == 5) obj = original;"
6657 ExpectString(code, "PASSED");
6661 THREADED_TEST(IndexedInterceptorOnProto) {
6662 v8::Isolate* isolate = CcTest::isolate();
6663 v8::HandleScope scope(isolate);
6664 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6665 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
6667 LocalContext context;
6668 Local<v8::Object> obj = templ->NewInstance();
6669 context->Global()->Set(v8_str("obj"), obj);
6672 "var o = {__proto__: obj};"
6674 " for (var i = 0; i < 100; i++) {"
6676 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;"
6682 ExpectString(code, "PASSED");
6686 THREADED_TEST(MultiContexts) {
6687 v8::Isolate* isolate = CcTest::isolate();
6688 v8::HandleScope scope(isolate);
6689 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6690 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(isolate,
6693 Local<String> password = v8_str("Password");
6695 // Create an environment
6696 LocalContext context0(0, templ);
6697 context0->SetSecurityToken(password);
6698 v8::Handle<v8::Object> global0 = context0->Global();
6699 global0->Set(v8_str("custom"), v8_num(1234));
6700 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6702 // Create an independent environment
6703 LocalContext context1(0, templ);
6704 context1->SetSecurityToken(password);
6705 v8::Handle<v8::Object> global1 = context1->Global();
6706 global1->Set(v8_str("custom"), v8_num(1234));
6707 CHECK_NE(global0, global1);
6708 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value());
6709 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value());
6711 // Now create a new context with the old global
6712 LocalContext context2(0, templ, global1);
6713 context2->SetSecurityToken(password);
6714 v8::Handle<v8::Object> global2 = context2->Global();
6715 CHECK_EQ(global1, global2);
6716 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value());
6717 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value());
6721 THREADED_TEST(FunctionPrototypeAcrossContexts) {
6722 // Make sure that functions created by cloning boilerplates cannot
6723 // communicate through their __proto__ field.
6725 v8::HandleScope scope(CcTest::isolate());
6728 v8::Handle<v8::Object> global0 =
6730 v8::Handle<v8::Object> object0 =
6731 global0->Get(v8_str("Object")).As<v8::Object>();
6732 v8::Handle<v8::Object> tostring0 =
6733 object0->Get(v8_str("toString")).As<v8::Object>();
6734 v8::Handle<v8::Object> proto0 =
6735 tostring0->Get(v8_str("__proto__")).As<v8::Object>();
6736 proto0->Set(v8_str("custom"), v8_num(1234));
6739 v8::Handle<v8::Object> global1 =
6741 v8::Handle<v8::Object> object1 =
6742 global1->Get(v8_str("Object")).As<v8::Object>();
6743 v8::Handle<v8::Object> tostring1 =
6744 object1->Get(v8_str("toString")).As<v8::Object>();
6745 v8::Handle<v8::Object> proto1 =
6746 tostring1->Get(v8_str("__proto__")).As<v8::Object>();
6747 CHECK(!proto1->Has(v8_str("custom")));
6751 THREADED_TEST(Regress892105) {
6752 // Make sure that object and array literals created by cloning
6753 // boilerplates cannot communicate through their __proto__
6754 // field. This is rather difficult to check, but we try to add stuff
6755 // to Object.prototype and Array.prototype and create a new
6756 // environment. This should succeed.
6758 v8::HandleScope scope(CcTest::isolate());
6760 Local<String> source = v8_str("Object.prototype.obj = 1234;"
6761 "Array.prototype.arr = 4567;"
6765 Local<Script> script0 = v8_compile(source);
6766 CHECK_EQ(8901.0, script0->Run()->NumberValue());
6769 Local<Script> script1 = v8_compile(source);
6770 CHECK_EQ(8901.0, script1->Run()->NumberValue());
6774 THREADED_TEST(UndetectableObject) {
6776 v8::HandleScope scope(env->GetIsolate());
6778 Local<v8::FunctionTemplate> desc =
6779 v8::FunctionTemplate::New(env->GetIsolate());
6780 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6782 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6783 env->Global()->Set(v8_str("undetectable"), obj);
6785 ExpectString("undetectable.toString()", "[object Object]");
6786 ExpectString("typeof undetectable", "undefined");
6787 ExpectString("typeof(undetectable)", "undefined");
6788 ExpectBoolean("typeof undetectable == 'undefined'", true);
6789 ExpectBoolean("typeof undetectable == 'object'", false);
6790 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6791 ExpectBoolean("!undetectable", true);
6793 ExpectObject("true&&undetectable", obj);
6794 ExpectBoolean("false&&undetectable", false);
6795 ExpectBoolean("true||undetectable", true);
6796 ExpectObject("false||undetectable", obj);
6798 ExpectObject("undetectable&&true", obj);
6799 ExpectObject("undetectable&&false", obj);
6800 ExpectBoolean("undetectable||true", true);
6801 ExpectBoolean("undetectable||false", false);
6803 ExpectBoolean("undetectable==null", true);
6804 ExpectBoolean("null==undetectable", true);
6805 ExpectBoolean("undetectable==undefined", true);
6806 ExpectBoolean("undefined==undetectable", true);
6807 ExpectBoolean("undetectable==undetectable", true);
6810 ExpectBoolean("undetectable===null", false);
6811 ExpectBoolean("null===undetectable", false);
6812 ExpectBoolean("undetectable===undefined", false);
6813 ExpectBoolean("undefined===undetectable", false);
6814 ExpectBoolean("undetectable===undetectable", true);
6818 THREADED_TEST(VoidLiteral) {
6820 v8::Isolate* isolate = env->GetIsolate();
6821 v8::HandleScope scope(isolate);
6823 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6824 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6826 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6827 env->Global()->Set(v8_str("undetectable"), obj);
6829 ExpectBoolean("undefined == void 0", true);
6830 ExpectBoolean("undetectable == void 0", true);
6831 ExpectBoolean("null == void 0", true);
6832 ExpectBoolean("undefined === void 0", true);
6833 ExpectBoolean("undetectable === void 0", false);
6834 ExpectBoolean("null === void 0", false);
6836 ExpectBoolean("void 0 == undefined", true);
6837 ExpectBoolean("void 0 == undetectable", true);
6838 ExpectBoolean("void 0 == null", true);
6839 ExpectBoolean("void 0 === undefined", true);
6840 ExpectBoolean("void 0 === undetectable", false);
6841 ExpectBoolean("void 0 === null", false);
6843 ExpectString("(function() {"
6845 " return x === void 0;"
6847 " return e.toString();"
6850 "ReferenceError: x is not defined");
6851 ExpectString("(function() {"
6853 " return void 0 === x;"
6855 " return e.toString();"
6858 "ReferenceError: x is not defined");
6862 THREADED_TEST(ExtensibleOnUndetectable) {
6864 v8::Isolate* isolate = env->GetIsolate();
6865 v8::HandleScope scope(isolate);
6867 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
6868 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable
6870 Local<v8::Object> obj = desc->GetFunction()->NewInstance();
6871 env->Global()->Set(v8_str("undetectable"), obj);
6873 Local<String> source = v8_str("undetectable.x = 42;"
6876 Local<Script> script = v8_compile(source);
6878 CHECK_EQ(v8::Integer::New(isolate, 42), script->Run());
6880 ExpectBoolean("Object.isExtensible(undetectable)", true);
6882 source = v8_str("Object.preventExtensions(undetectable);");
6883 script = v8_compile(source);
6885 ExpectBoolean("Object.isExtensible(undetectable)", false);
6887 source = v8_str("undetectable.y = 2000;");
6888 script = v8_compile(source);
6890 ExpectBoolean("undetectable.y == undefined", true);
6895 THREADED_TEST(UndetectableString) {
6897 v8::HandleScope scope(env->GetIsolate());
6899 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6900 String::kUndetectableString);
6901 env->Global()->Set(v8_str("undetectable"), obj);
6903 ExpectString("undetectable", "foo");
6904 ExpectString("typeof undetectable", "undefined");
6905 ExpectString("typeof(undetectable)", "undefined");
6906 ExpectBoolean("typeof undetectable == 'undefined'", true);
6907 ExpectBoolean("typeof undetectable == 'string'", false);
6908 ExpectBoolean("if (undetectable) { true; } else { false; }", false);
6909 ExpectBoolean("!undetectable", true);
6911 ExpectObject("true&&undetectable", obj);
6912 ExpectBoolean("false&&undetectable", false);
6913 ExpectBoolean("true||undetectable", true);
6914 ExpectObject("false||undetectable", obj);
6916 ExpectObject("undetectable&&true", obj);
6917 ExpectObject("undetectable&&false", obj);
6918 ExpectBoolean("undetectable||true", true);
6919 ExpectBoolean("undetectable||false", false);
6921 ExpectBoolean("undetectable==null", true);
6922 ExpectBoolean("null==undetectable", true);
6923 ExpectBoolean("undetectable==undefined", true);
6924 ExpectBoolean("undefined==undetectable", true);
6925 ExpectBoolean("undetectable==undetectable", true);
6928 ExpectBoolean("undetectable===null", false);
6929 ExpectBoolean("null===undetectable", false);
6930 ExpectBoolean("undetectable===undefined", false);
6931 ExpectBoolean("undefined===undetectable", false);
6932 ExpectBoolean("undetectable===undetectable", true);
6936 TEST(UndetectableOptimized) {
6937 i::FLAG_allow_natives_syntax = true;
6939 v8::HandleScope scope(env->GetIsolate());
6941 Local<String> obj = String::NewFromUtf8(env->GetIsolate(), "foo",
6942 String::kUndetectableString);
6943 env->Global()->Set(v8_str("undetectable"), obj);
6944 env->Global()->Set(v8_str("detectable"), v8_str("bar"));
6947 "function testBranch() {"
6948 " if (!%_IsUndetectableObject(undetectable)) throw 1;"
6949 " if (%_IsUndetectableObject(detectable)) throw 2;"
6951 "function testBool() {"
6952 " var b1 = !%_IsUndetectableObject(undetectable);"
6953 " var b2 = %_IsUndetectableObject(detectable);"
6958 "%OptimizeFunctionOnNextCall(testBranch);"
6959 "%OptimizeFunctionOnNextCall(testBool);"
6960 "for (var i = 0; i < 10; i++) {"
6969 // The point of this test is type checking. We run it only so compilers
6970 // don't complain about an unused function.
6971 TEST(PersistentHandles) {
6973 v8::Isolate* isolate = CcTest::isolate();
6974 v8::HandleScope scope(isolate);
6975 Local<String> str = v8_str("foo");
6976 v8::Persistent<String> p_str(isolate, str);
6978 Local<Script> scr = v8_compile("");
6979 v8::Persistent<Script> p_scr(isolate, scr);
6981 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
6982 v8::Persistent<ObjectTemplate> p_templ(isolate, templ);
6987 static void HandleLogDelegator(
6988 const v8::FunctionCallbackInfo<v8::Value>& args) {
6989 ApiTestFuzzer::Fuzz();
6993 THREADED_TEST(GlobalObjectTemplate) {
6994 v8::Isolate* isolate = CcTest::isolate();
6995 v8::HandleScope handle_scope(isolate);
6996 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
6997 global_template->Set(v8_str("JSNI_Log"),
6998 v8::FunctionTemplate::New(isolate, HandleLogDelegator));
6999 v8::Local<Context> context = Context::New(isolate, 0, global_template);
7000 Context::Scope context_scope(context);
7001 CompileRun("JSNI_Log('LOG')");
7005 static const char* kSimpleExtensionSource =
7011 TEST(SimpleExtensions) {
7012 v8::HandleScope handle_scope(CcTest::isolate());
7013 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource));
7014 const char* extension_names[] = { "simpletest" };
7015 v8::ExtensionConfiguration extensions(1, extension_names);
7016 v8::Handle<Context> context =
7017 Context::New(CcTest::isolate(), &extensions);
7018 Context::Scope lock(context);
7019 v8::Handle<Value> result = CompileRun("Foo()");
7020 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7024 static const char* kStackTraceFromExtensionSource =
7026 " throw new Error();"
7033 TEST(StackTraceInExtension) {
7034 v8::HandleScope handle_scope(CcTest::isolate());
7035 v8::RegisterExtension(new Extension("stacktracetest",
7036 kStackTraceFromExtensionSource));
7037 const char* extension_names[] = { "stacktracetest" };
7038 v8::ExtensionConfiguration extensions(1, extension_names);
7039 v8::Handle<Context> context =
7040 Context::New(CcTest::isolate(), &extensions);
7041 Context::Scope lock(context);
7042 CompileRun("function user() { bar(); }"
7044 "try{ user(); } catch (e) { error = e; }");
7045 CHECK_EQ(-1, CompileRun("error.stack.indexOf('foo')")->Int32Value());
7046 CHECK_EQ(-1, CompileRun("error.stack.indexOf('bar')")->Int32Value());
7047 CHECK_NE(-1, CompileRun("error.stack.indexOf('user')")->Int32Value());
7051 TEST(NullExtensions) {
7052 v8::HandleScope handle_scope(CcTest::isolate());
7053 v8::RegisterExtension(new Extension("nulltest", NULL));
7054 const char* extension_names[] = { "nulltest" };
7055 v8::ExtensionConfiguration extensions(1, extension_names);
7056 v8::Handle<Context> context =
7057 Context::New(CcTest::isolate(), &extensions);
7058 Context::Scope lock(context);
7059 v8::Handle<Value> result = CompileRun("1+3");
7060 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7064 static const char* kEmbeddedExtensionSource =
7065 "function Ret54321(){return 54321;}~~@@$"
7066 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS.";
7067 static const int kEmbeddedExtensionSourceValidLen = 34;
7070 TEST(ExtensionMissingSourceLength) {
7071 v8::HandleScope handle_scope(CcTest::isolate());
7072 v8::RegisterExtension(new Extension("srclentest_fail",
7073 kEmbeddedExtensionSource));
7074 const char* extension_names[] = { "srclentest_fail" };
7075 v8::ExtensionConfiguration extensions(1, extension_names);
7076 v8::Handle<Context> context =
7077 Context::New(CcTest::isolate(), &extensions);
7078 CHECK_EQ(0, *context);
7082 TEST(ExtensionWithSourceLength) {
7083 for (int source_len = kEmbeddedExtensionSourceValidLen - 1;
7084 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) {
7085 v8::HandleScope handle_scope(CcTest::isolate());
7086 i::ScopedVector<char> extension_name(32);
7087 i::SNPrintF(extension_name, "ext #%d", source_len);
7088 v8::RegisterExtension(new Extension(extension_name.start(),
7089 kEmbeddedExtensionSource, 0, 0,
7091 const char* extension_names[1] = { extension_name.start() };
7092 v8::ExtensionConfiguration extensions(1, extension_names);
7093 v8::Handle<Context> context =
7094 Context::New(CcTest::isolate(), &extensions);
7095 if (source_len == kEmbeddedExtensionSourceValidLen) {
7096 Context::Scope lock(context);
7097 v8::Handle<Value> result = CompileRun("Ret54321()");
7098 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 54321), result);
7100 // Anything but exactly the right length should fail to compile.
7101 CHECK_EQ(0, *context);
7107 static const char* kEvalExtensionSource1 =
7108 "function UseEval1() {"
7110 " return eval('x');"
7114 static const char* kEvalExtensionSource2 =
7118 " return eval('x');"
7120 " this.UseEval2 = e;"
7124 TEST(UseEvalFromExtension) {
7125 v8::HandleScope handle_scope(CcTest::isolate());
7126 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1));
7127 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2));
7128 const char* extension_names[] = { "evaltest1", "evaltest2" };
7129 v8::ExtensionConfiguration extensions(2, extension_names);
7130 v8::Handle<Context> context =
7131 Context::New(CcTest::isolate(), &extensions);
7132 Context::Scope lock(context);
7133 v8::Handle<Value> result = CompileRun("UseEval1()");
7134 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7135 result = CompileRun("UseEval2()");
7136 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7140 static const char* kWithExtensionSource1 =
7141 "function UseWith1() {"
7143 " with({x:87}) { return x; }"
7148 static const char* kWithExtensionSource2 =
7152 " with ({x:87}) { return x; }"
7154 " this.UseWith2 = e;"
7158 TEST(UseWithFromExtension) {
7159 v8::HandleScope handle_scope(CcTest::isolate());
7160 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1));
7161 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2));
7162 const char* extension_names[] = { "withtest1", "withtest2" };
7163 v8::ExtensionConfiguration extensions(2, extension_names);
7164 v8::Handle<Context> context =
7165 Context::New(CcTest::isolate(), &extensions);
7166 Context::Scope lock(context);
7167 v8::Handle<Value> result = CompileRun("UseWith1()");
7168 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7169 result = CompileRun("UseWith2()");
7170 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 87));
7174 TEST(AutoExtensions) {
7175 v8::HandleScope handle_scope(CcTest::isolate());
7176 Extension* extension = new Extension("autotest", kSimpleExtensionSource);
7177 extension->set_auto_enable(true);
7178 v8::RegisterExtension(extension);
7179 v8::Handle<Context> context =
7180 Context::New(CcTest::isolate());
7181 Context::Scope lock(context);
7182 v8::Handle<Value> result = CompileRun("Foo()");
7183 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 4));
7187 static const char* kSyntaxErrorInExtensionSource =
7191 // Test that a syntax error in an extension does not cause a fatal
7192 // error but results in an empty context.
7193 TEST(SyntaxErrorExtensions) {
7194 v8::HandleScope handle_scope(CcTest::isolate());
7195 v8::RegisterExtension(new Extension("syntaxerror",
7196 kSyntaxErrorInExtensionSource));
7197 const char* extension_names[] = { "syntaxerror" };
7198 v8::ExtensionConfiguration extensions(1, extension_names);
7199 v8::Handle<Context> context =
7200 Context::New(CcTest::isolate(), &extensions);
7201 CHECK(context.IsEmpty());
7205 static const char* kExceptionInExtensionSource =
7209 // Test that an exception when installing an extension does not cause
7210 // a fatal error but results in an empty context.
7211 TEST(ExceptionExtensions) {
7212 v8::HandleScope handle_scope(CcTest::isolate());
7213 v8::RegisterExtension(new Extension("exception",
7214 kExceptionInExtensionSource));
7215 const char* extension_names[] = { "exception" };
7216 v8::ExtensionConfiguration extensions(1, extension_names);
7217 v8::Handle<Context> context =
7218 Context::New(CcTest::isolate(), &extensions);
7219 CHECK(context.IsEmpty());
7223 static const char* kNativeCallInExtensionSource =
7224 "function call_runtime_last_index_of(x) {"
7225 " return %StringLastIndexOf(x, 'bob', 10);"
7229 static const char* kNativeCallTest =
7230 "call_runtime_last_index_of('bobbobboellebobboellebobbob');";
7232 // Test that a native runtime calls are supported in extensions.
7233 TEST(NativeCallInExtensions) {
7234 v8::HandleScope handle_scope(CcTest::isolate());
7235 v8::RegisterExtension(new Extension("nativecall",
7236 kNativeCallInExtensionSource));
7237 const char* extension_names[] = { "nativecall" };
7238 v8::ExtensionConfiguration extensions(1, extension_names);
7239 v8::Handle<Context> context =
7240 Context::New(CcTest::isolate(), &extensions);
7241 Context::Scope lock(context);
7242 v8::Handle<Value> result = CompileRun(kNativeCallTest);
7243 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 3));
7247 class NativeFunctionExtension : public Extension {
7249 NativeFunctionExtension(const char* name,
7251 v8::FunctionCallback fun = &Echo)
7252 : Extension(name, source),
7255 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7256 v8::Isolate* isolate,
7257 v8::Handle<v8::String> name) {
7258 return v8::FunctionTemplate::New(isolate, function_);
7261 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) {
7262 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]);
7265 v8::FunctionCallback function_;
7269 TEST(NativeFunctionDeclaration) {
7270 v8::HandleScope handle_scope(CcTest::isolate());
7271 const char* name = "nativedecl";
7272 v8::RegisterExtension(new NativeFunctionExtension(name,
7273 "native function foo();"));
7274 const char* extension_names[] = { name };
7275 v8::ExtensionConfiguration extensions(1, extension_names);
7276 v8::Handle<Context> context =
7277 Context::New(CcTest::isolate(), &extensions);
7278 Context::Scope lock(context);
7279 v8::Handle<Value> result = CompileRun("foo(42);");
7280 CHECK_EQ(result, v8::Integer::New(CcTest::isolate(), 42));
7284 TEST(NativeFunctionDeclarationError) {
7285 v8::HandleScope handle_scope(CcTest::isolate());
7286 const char* name = "nativedeclerr";
7287 // Syntax error in extension code.
7288 v8::RegisterExtension(new NativeFunctionExtension(name,
7289 "native\nfunction foo();"));
7290 const char* extension_names[] = { name };
7291 v8::ExtensionConfiguration extensions(1, extension_names);
7292 v8::Handle<Context> context =
7293 Context::New(CcTest::isolate(), &extensions);
7294 CHECK(context.IsEmpty());
7298 TEST(NativeFunctionDeclarationErrorEscape) {
7299 v8::HandleScope handle_scope(CcTest::isolate());
7300 const char* name = "nativedeclerresc";
7301 // Syntax error in extension code - escape code in "native" means that
7302 // it's not treated as a keyword.
7303 v8::RegisterExtension(new NativeFunctionExtension(
7305 "nativ\\u0065 function foo();"));
7306 const char* extension_names[] = { name };
7307 v8::ExtensionConfiguration extensions(1, extension_names);
7308 v8::Handle<Context> context =
7309 Context::New(CcTest::isolate(), &extensions);
7310 CHECK(context.IsEmpty());
7314 static void CheckDependencies(const char* name, const char* expected) {
7315 v8::HandleScope handle_scope(CcTest::isolate());
7316 v8::ExtensionConfiguration config(1, &name);
7317 LocalContext context(&config);
7318 CHECK_EQ(String::NewFromUtf8(CcTest::isolate(), expected),
7319 context->Global()->Get(v8_str("loaded")));
7330 THREADED_TEST(ExtensionDependency) {
7331 static const char* kEDeps[] = { "D" };
7332 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps));
7333 static const char* kDDeps[] = { "B", "C" };
7334 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps));
7335 static const char* kBCDeps[] = { "A" };
7336 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps));
7337 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps));
7338 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';"));
7339 CheckDependencies("A", "undefinedA");
7340 CheckDependencies("B", "undefinedAB");
7341 CheckDependencies("C", "undefinedAC");
7342 CheckDependencies("D", "undefinedABCD");
7343 CheckDependencies("E", "undefinedABCDE");
7344 v8::HandleScope handle_scope(CcTest::isolate());
7345 static const char* exts[2] = { "C", "E" };
7346 v8::ExtensionConfiguration config(2, exts);
7347 LocalContext context(&config);
7348 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded")));
7352 static const char* kExtensionTestScript =
7353 "native function A();"
7354 "native function B();"
7355 "native function C();"
7357 " if (i == 0) return A();"
7358 " if (i == 1) return B();"
7359 " if (i == 2) return C();"
7363 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) {
7364 ApiTestFuzzer::Fuzz();
7365 if (args.IsConstructCall()) {
7366 args.This()->Set(v8_str("data"), args.Data());
7367 args.GetReturnValue().SetNull();
7370 args.GetReturnValue().Set(args.Data());
7374 class FunctionExtension : public Extension {
7376 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { }
7377 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
7378 v8::Isolate* isolate,
7379 v8::Handle<String> name);
7383 static int lookup_count = 0;
7384 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunctionTemplate(
7385 v8::Isolate* isolate, v8::Handle<String> name) {
7387 if (name->Equals(v8_str("A"))) {
7388 return v8::FunctionTemplate::New(
7389 isolate, CallFun, v8::Integer::New(isolate, 8));
7390 } else if (name->Equals(v8_str("B"))) {
7391 return v8::FunctionTemplate::New(
7392 isolate, CallFun, v8::Integer::New(isolate, 7));
7393 } else if (name->Equals(v8_str("C"))) {
7394 return v8::FunctionTemplate::New(
7395 isolate, CallFun, v8::Integer::New(isolate, 6));
7397 return v8::Handle<v8::FunctionTemplate>();
7402 THREADED_TEST(FunctionLookup) {
7403 v8::RegisterExtension(new FunctionExtension());
7404 v8::HandleScope handle_scope(CcTest::isolate());
7405 static const char* exts[1] = { "functiontest" };
7406 v8::ExtensionConfiguration config(1, exts);
7407 LocalContext context(&config);
7408 CHECK_EQ(3, lookup_count);
7409 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7410 CompileRun("Foo(0)"));
7411 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7412 CompileRun("Foo(1)"));
7413 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7414 CompileRun("Foo(2)"));
7418 THREADED_TEST(NativeFunctionConstructCall) {
7419 v8::RegisterExtension(new FunctionExtension());
7420 v8::HandleScope handle_scope(CcTest::isolate());
7421 static const char* exts[1] = { "functiontest" };
7422 v8::ExtensionConfiguration config(1, exts);
7423 LocalContext context(&config);
7424 for (int i = 0; i < 10; i++) {
7425 // Run a few times to ensure that allocation of objects doesn't
7426 // change behavior of a constructor function.
7427 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 8),
7428 CompileRun("(new A()).data"));
7429 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 7),
7430 CompileRun("(new B()).data"));
7431 CHECK_EQ(v8::Integer::New(CcTest::isolate(), 6),
7432 CompileRun("(new C()).data"));
7437 static const char* last_location;
7438 static const char* last_message;
7439 void StoringErrorCallback(const char* location, const char* message) {
7440 if (last_location == NULL) {
7441 last_location = location;
7442 last_message = message;
7447 // ErrorReporting creates a circular extensions configuration and
7448 // tests that the fatal error handler gets called. This renders V8
7449 // unusable and therefore this test cannot be run in parallel.
7450 TEST(ErrorReporting) {
7451 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
7452 static const char* aDeps[] = { "B" };
7453 v8::RegisterExtension(new Extension("A", "", 1, aDeps));
7454 static const char* bDeps[] = { "A" };
7455 v8::RegisterExtension(new Extension("B", "", 1, bDeps));
7456 last_location = NULL;
7457 v8::ExtensionConfiguration config(1, bDeps);
7458 v8::Handle<Context> context =
7459 Context::New(CcTest::isolate(), &config);
7460 CHECK(context.IsEmpty());
7461 CHECK_NE(last_location, NULL);
7465 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message,
7466 v8::Handle<Value> data) {
7467 CHECK(message->GetScriptOrigin().ResourceName()->IsUndefined());
7468 CHECK_EQ(v8::Undefined(CcTest::isolate()),
7469 message->GetScriptOrigin().ResourceName());
7470 message->GetLineNumber();
7471 message->GetSourceLine();
7475 THREADED_TEST(ErrorWithMissingScriptInfo) {
7476 LocalContext context;
7477 v8::HandleScope scope(context->GetIsolate());
7478 v8::V8::AddMessageListener(MissingScriptInfoMessageListener);
7479 CompileRun("throw Error()");
7480 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener);
7484 struct FlagAndPersistent {
7486 v8::Persistent<v8::Object> handle;
7490 static void SetFlag(
7491 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7492 data.GetParameter()->flag = true;
7496 static void IndependentWeakHandle(bool global_gc, bool interlinked) {
7497 v8::Isolate* iso = CcTest::isolate();
7498 v8::HandleScope scope(iso);
7499 v8::Handle<Context> context = Context::New(iso);
7500 Context::Scope context_scope(context);
7502 FlagAndPersistent object_a, object_b;
7504 intptr_t big_heap_size;
7507 v8::HandleScope handle_scope(iso);
7508 Local<Object> a(v8::Object::New(iso));
7509 Local<Object> b(v8::Object::New(iso));
7510 object_a.handle.Reset(iso, a);
7511 object_b.handle.Reset(iso, b);
7513 a->Set(v8_str("x"), b);
7514 b->Set(v8_str("x"), a);
7517 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7519 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7521 // We are relying on this creating a big flag array and reserving the space
7523 v8::Handle<Value> big_array = CompileRun("new Array(50000)");
7524 a->Set(v8_str("y"), big_array);
7525 big_heap_size = CcTest::heap()->SizeOfObjects();
7528 object_a.flag = false;
7529 object_b.flag = false;
7530 object_a.handle.SetPhantom(&object_a, &SetFlag);
7531 object_b.handle.SetPhantom(&object_b, &SetFlag);
7532 CHECK(!object_b.handle.IsIndependent());
7533 object_a.handle.MarkIndependent();
7534 object_b.handle.MarkIndependent();
7535 CHECK(object_b.handle.IsIndependent());
7537 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7539 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7541 // A single GC should be enough to reclaim the memory, since we are using
7543 CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
7544 CHECK(object_a.flag);
7545 CHECK(object_b.flag);
7549 THREADED_TEST(IndependentWeakHandle) {
7550 IndependentWeakHandle(false, false);
7551 IndependentWeakHandle(false, true);
7552 IndependentWeakHandle(true, false);
7553 IndependentWeakHandle(true, true);
7557 static void ResetUseValueAndSetFlag(
7558 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7559 // Blink will reset the handle, and then use the other handle, so they
7560 // can't use the same backing slot.
7561 data.GetParameter()->handle.Reset();
7562 data.GetValue()->IsBoolean(); // Make sure the handle still works.
7563 data.GetParameter()->flag = true;
7567 static void ResetWeakHandle(bool global_gc) {
7568 v8::Isolate* iso = CcTest::isolate();
7569 v8::HandleScope scope(iso);
7570 v8::Handle<Context> context = Context::New(iso);
7571 Context::Scope context_scope(context);
7573 FlagAndPersistent object_a, object_b;
7576 v8::HandleScope handle_scope(iso);
7577 Local<Object> a(v8::Object::New(iso));
7578 Local<Object> b(v8::Object::New(iso));
7579 object_a.handle.Reset(iso, a);
7580 object_b.handle.Reset(iso, b);
7582 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7584 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7588 object_a.flag = false;
7589 object_b.flag = false;
7590 object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
7591 object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
7593 object_a.handle.MarkIndependent();
7594 object_b.handle.MarkIndependent();
7595 CHECK(object_b.handle.IsIndependent());
7598 CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
7600 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7602 CHECK(object_a.flag);
7603 CHECK(object_b.flag);
7607 THREADED_TEST(ResetWeakHandle) {
7608 ResetWeakHandle(false);
7609 ResetWeakHandle(true);
7613 static void InvokeScavenge() {
7614 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7618 static void InvokeMarkSweep() {
7619 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7623 static void ForceScavenge(
7624 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7625 data.GetParameter()->handle.Reset();
7626 data.GetParameter()->flag = true;
7631 static void ForceMarkSweep(
7632 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7633 data.GetParameter()->handle.Reset();
7634 data.GetParameter()->flag = true;
7639 THREADED_TEST(GCFromWeakCallbacks) {
7640 v8::Isolate* isolate = CcTest::isolate();
7641 v8::HandleScope scope(isolate);
7642 v8::Handle<Context> context = Context::New(isolate);
7643 Context::Scope context_scope(context);
7645 static const int kNumberOfGCTypes = 2;
7646 typedef v8::WeakCallbackData<v8::Object, FlagAndPersistent>::Callback
7648 Callback gc_forcing_callback[kNumberOfGCTypes] =
7649 {&ForceScavenge, &ForceMarkSweep};
7651 typedef void (*GCInvoker)();
7652 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep};
7654 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) {
7655 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) {
7656 FlagAndPersistent object;
7658 v8::HandleScope handle_scope(isolate);
7659 object.handle.Reset(isolate, v8::Object::New(isolate));
7661 object.flag = false;
7662 object.handle.SetWeak(&object, gc_forcing_callback[inner_gc]);
7663 object.handle.MarkIndependent();
7664 invoke_gc[outer_gc]();
7671 static void RevivingCallback(
7672 const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
7673 data.GetParameter()->handle.ClearWeak();
7674 data.GetParameter()->flag = true;
7678 THREADED_TEST(IndependentHandleRevival) {
7679 v8::Isolate* isolate = CcTest::isolate();
7680 v8::HandleScope scope(isolate);
7681 v8::Handle<Context> context = Context::New(isolate);
7682 Context::Scope context_scope(context);
7684 FlagAndPersistent object;
7686 v8::HandleScope handle_scope(isolate);
7687 v8::Local<v8::Object> o = v8::Object::New(isolate);
7688 object.handle.Reset(isolate, o);
7689 o->Set(v8_str("x"), v8::Integer::New(isolate, 1));
7690 v8::Local<String> y_str = v8_str("y");
7691 o->Set(y_str, y_str);
7693 object.flag = false;
7694 object.handle.SetWeak(&object, &RevivingCallback);
7695 object.handle.MarkIndependent();
7696 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
7698 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
7700 v8::HandleScope handle_scope(isolate);
7701 v8::Local<v8::Object> o =
7702 v8::Local<v8::Object>::New(isolate, object.handle);
7703 v8::Local<String> y_str = v8_str("y");
7704 CHECK_EQ(v8::Integer::New(isolate, 1), o->Get(v8_str("x")));
7705 CHECK(o->Get(y_str)->Equals(y_str));
7710 v8::Handle<Function> args_fun;
7713 static void ArgumentsTestCallback(
7714 const v8::FunctionCallbackInfo<v8::Value>& args) {
7715 ApiTestFuzzer::Fuzz();
7716 v8::Isolate* isolate = args.GetIsolate();
7717 CHECK_EQ(args_fun, args.Callee());
7718 CHECK_EQ(3, args.Length());
7719 CHECK_EQ(v8::Integer::New(isolate, 1), args[0]);
7720 CHECK_EQ(v8::Integer::New(isolate, 2), args[1]);
7721 CHECK_EQ(v8::Integer::New(isolate, 3), args[2]);
7722 CHECK_EQ(v8::Undefined(isolate), args[3]);
7723 v8::HandleScope scope(args.GetIsolate());
7724 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
7728 THREADED_TEST(Arguments) {
7729 v8::Isolate* isolate = CcTest::isolate();
7730 v8::HandleScope scope(isolate);
7731 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(isolate);
7732 global->Set(v8_str("f"),
7733 v8::FunctionTemplate::New(isolate, ArgumentsTestCallback));
7734 LocalContext context(NULL, global);
7735 args_fun = context->Global()->Get(v8_str("f")).As<Function>();
7736 v8_compile("f(1, 2, 3)")->Run();
7740 static void NoBlockGetterX(Local<String> name,
7741 const v8::PropertyCallbackInfo<v8::Value>&) {
7745 static void NoBlockGetterI(uint32_t index,
7746 const v8::PropertyCallbackInfo<v8::Value>&) {
7750 static void PDeleter(Local<String> name,
7751 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7752 if (!name->Equals(v8_str("foo"))) {
7753 return; // not intercepted
7756 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7760 static void IDeleter(uint32_t index,
7761 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
7763 return; // not intercepted
7766 info.GetReturnValue().Set(false); // intercepted, don't delete the property
7770 THREADED_TEST(Deleter) {
7771 v8::Isolate* isolate = CcTest::isolate();
7772 v8::HandleScope scope(isolate);
7773 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7774 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
7775 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
7776 LocalContext context;
7777 context->Global()->Set(v8_str("k"), obj->NewInstance());
7783 CHECK(v8_compile("delete k.foo")->Run()->IsFalse());
7784 CHECK(v8_compile("delete k.bar")->Run()->IsTrue());
7786 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo"));
7787 CHECK(v8_compile("k.bar")->Run()->IsUndefined());
7789 CHECK(v8_compile("delete k[2]")->Run()->IsFalse());
7790 CHECK(v8_compile("delete k[4]")->Run()->IsTrue());
7792 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2));
7793 CHECK(v8_compile("k[4]")->Run()->IsUndefined());
7797 static void GetK(Local<String> name,
7798 const v8::PropertyCallbackInfo<v8::Value>& info) {
7799 ApiTestFuzzer::Fuzz();
7800 if (name->Equals(v8_str("foo")) ||
7801 name->Equals(v8_str("bar")) ||
7802 name->Equals(v8_str("baz"))) {
7803 info.GetReturnValue().SetUndefined();
7808 static void IndexedGetK(uint32_t index,
7809 const v8::PropertyCallbackInfo<v8::Value>& info) {
7810 ApiTestFuzzer::Fuzz();
7811 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined();
7815 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7816 ApiTestFuzzer::Fuzz();
7817 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
7818 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("foo"));
7819 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("bar"));
7820 result->Set(v8::Integer::New(info.GetIsolate(), 2), v8_str("baz"));
7821 info.GetReturnValue().Set(result);
7825 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
7826 ApiTestFuzzer::Fuzz();
7827 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
7828 result->Set(v8::Integer::New(info.GetIsolate(), 0), v8_str("0"));
7829 result->Set(v8::Integer::New(info.GetIsolate(), 1), v8_str("1"));
7830 info.GetReturnValue().Set(result);
7834 THREADED_TEST(Enumerators) {
7835 v8::Isolate* isolate = CcTest::isolate();
7836 v8::HandleScope scope(isolate);
7837 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7838 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
7839 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
7840 LocalContext context;
7841 context->Global()->Set(v8_str("k"), obj->NewInstance());
7842 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
7847 "k[4294967295] = 0;"
7849 "k[4294967296] = 0;"
7853 "k[30000000000] = 0;"
7856 "for (var prop in k) {"
7857 " result.push(prop);"
7860 // Check that we get all the property names returned including the
7861 // ones from the enumerators in the right order: indexed properties
7862 // in numerical order, indexed interceptor properties, named
7863 // properties in insertion order, named interceptor properties.
7864 // This order is not mandated by the spec, so this test is just
7865 // documenting our behavior.
7866 CHECK_EQ(17, result->Length());
7867 // Indexed properties in numerical order.
7868 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(isolate, 0)));
7869 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(isolate, 1)));
7870 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(isolate, 2)));
7871 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(isolate, 3)));
7872 // Indexed interceptor properties in the order they are returned
7873 // from the enumerator interceptor.
7874 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(isolate, 4)));
7875 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(isolate, 5)));
7876 // Named properties in insertion order.
7877 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(isolate, 6)));
7878 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(isolate, 7)));
7879 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(isolate, 8)));
7880 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(isolate, 9)));
7881 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(isolate, 10)));
7882 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(isolate, 11)));
7883 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(isolate, 12)));
7884 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(isolate, 13)));
7885 // Named interceptor properties.
7886 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(isolate, 14)));
7887 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(isolate, 15)));
7888 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(isolate, 16)));
7893 int p_getter_count2;
7896 static void PGetter(Local<String> name,
7897 const v8::PropertyCallbackInfo<v8::Value>& info) {
7898 ApiTestFuzzer::Fuzz();
7900 v8::Handle<v8::Object> global =
7901 info.GetIsolate()->GetCurrentContext()->Global();
7902 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7903 if (name->Equals(v8_str("p1"))) {
7904 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7905 } else if (name->Equals(v8_str("p2"))) {
7906 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7907 } else if (name->Equals(v8_str("p3"))) {
7908 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7909 } else if (name->Equals(v8_str("p4"))) {
7910 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7915 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) {
7916 ApiTestFuzzer::Fuzz();
7917 LocalContext context;
7918 context->Global()->Set(v8_str("o1"), obj->NewInstance());
7920 "o1.__proto__ = { };"
7921 "var o2 = { __proto__: o1 };"
7922 "var o3 = { __proto__: o2 };"
7923 "var o4 = { __proto__: o3 };"
7924 "for (var i = 0; i < 10; i++) o4.p4;"
7925 "for (var i = 0; i < 10; i++) o3.p3;"
7926 "for (var i = 0; i < 10; i++) o2.p2;"
7927 "for (var i = 0; i < 10; i++) o1.p1;");
7931 static void PGetter2(Local<String> name,
7932 const v8::PropertyCallbackInfo<v8::Value>& info) {
7933 ApiTestFuzzer::Fuzz();
7935 v8::Handle<v8::Object> global =
7936 info.GetIsolate()->GetCurrentContext()->Global();
7937 CHECK_EQ(info.Holder(), global->Get(v8_str("o1")));
7938 if (name->Equals(v8_str("p1"))) {
7939 CHECK_EQ(info.This(), global->Get(v8_str("o1")));
7940 } else if (name->Equals(v8_str("p2"))) {
7941 CHECK_EQ(info.This(), global->Get(v8_str("o2")));
7942 } else if (name->Equals(v8_str("p3"))) {
7943 CHECK_EQ(info.This(), global->Get(v8_str("o3")));
7944 } else if (name->Equals(v8_str("p4"))) {
7945 CHECK_EQ(info.This(), global->Get(v8_str("o4")));
7950 THREADED_TEST(GetterHolders) {
7951 v8::Isolate* isolate = CcTest::isolate();
7952 v8::HandleScope scope(isolate);
7953 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7954 obj->SetAccessor(v8_str("p1"), PGetter);
7955 obj->SetAccessor(v8_str("p2"), PGetter);
7956 obj->SetAccessor(v8_str("p3"), PGetter);
7957 obj->SetAccessor(v8_str("p4"), PGetter);
7960 CHECK_EQ(40, p_getter_count);
7964 THREADED_TEST(PreInterceptorHolders) {
7965 v8::Isolate* isolate = CcTest::isolate();
7966 v8::HandleScope scope(isolate);
7967 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
7968 obj->SetNamedPropertyHandler(PGetter2);
7969 p_getter_count2 = 0;
7971 CHECK_EQ(40, p_getter_count2);
7975 THREADED_TEST(ObjectInstantiation) {
7976 v8::Isolate* isolate = CcTest::isolate();
7977 v8::HandleScope scope(isolate);
7978 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
7979 templ->SetAccessor(v8_str("t"), PGetter2);
7980 LocalContext context;
7981 context->Global()->Set(v8_str("o"), templ->NewInstance());
7982 for (int i = 0; i < 100; i++) {
7983 v8::HandleScope inner_scope(CcTest::isolate());
7984 v8::Handle<v8::Object> obj = templ->NewInstance();
7985 CHECK_NE(obj, context->Global()->Get(v8_str("o")));
7986 context->Global()->Set(v8_str("o2"), obj);
7987 v8::Handle<Value> value =
7988 CompileRun("o.__proto__ === o2.__proto__");
7989 CHECK_EQ(v8::True(isolate), value);
7990 context->Global()->Set(v8_str("o"), obj);
7995 static int StrCmp16(uint16_t* a, uint16_t* b) {
7997 if (*a == 0 && *b == 0) return 0;
7998 if (*a != *b) return 0 + *a - *b;
8005 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) {
8007 if (n-- == 0) return 0;
8008 if (*a == 0 && *b == 0) return 0;
8009 if (*a != *b) return 0 + *a - *b;
8016 int GetUtf8Length(Handle<String> str) {
8017 int len = str->Utf8Length();
8019 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str));
8020 i::String::Flatten(istr);
8021 len = str->Utf8Length();
8027 THREADED_TEST(StringWrite) {
8028 LocalContext context;
8029 v8::HandleScope scope(context->GetIsolate());
8030 v8::Handle<String> str = v8_str("abcde");
8031 // abc<Icelandic eth><Unicode snowman>.
8032 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203");
8033 v8::Handle<String> str3 = v8::String::NewFromUtf8(
8034 context->GetIsolate(), "abc\0def", v8::String::kNormalString, 7);
8035 // "ab" + lead surrogate + "cd" + trail surrogate + "ef"
8036 uint16_t orphans[8] = { 0x61, 0x62, 0xd800, 0x63, 0x64, 0xdc00, 0x65, 0x66 };
8037 v8::Handle<String> orphans_str = v8::String::NewFromTwoByte(
8038 context->GetIsolate(), orphans, v8::String::kNormalString, 8);
8039 // single lead surrogate
8040 uint16_t lead[1] = { 0xd800 };
8041 v8::Handle<String> lead_str = v8::String::NewFromTwoByte(
8042 context->GetIsolate(), lead, v8::String::kNormalString, 1);
8043 // single trail surrogate
8044 uint16_t trail[1] = { 0xdc00 };
8045 v8::Handle<String> trail_str = v8::String::NewFromTwoByte(
8046 context->GetIsolate(), trail, v8::String::kNormalString, 1);
8048 uint16_t pair[2] = { 0xd800, 0xdc00 };
8049 v8::Handle<String> pair_str = v8::String::NewFromTwoByte(
8050 context->GetIsolate(), pair, v8::String::kNormalString, 2);
8051 const int kStride = 4; // Must match stride in for loops in JS below.
8054 "for (var i = 0; i < 0xd800; i += 4) {"
8055 " left = left + String.fromCharCode(i);"
8059 "for (var i = 0; i < 0xd800; i += 4) {"
8060 " right = String.fromCharCode(i) + right;"
8062 v8::Handle<v8::Object> global = context->Global();
8063 Handle<String> left_tree = global->Get(v8_str("left")).As<String>();
8064 Handle<String> right_tree = global->Get(v8_str("right")).As<String>();
8066 CHECK_EQ(5, str2->Length());
8067 CHECK_EQ(0xd800 / kStride, left_tree->Length());
8068 CHECK_EQ(0xd800 / kStride, right_tree->Length());
8071 char utf8buf[0xd800 * 3];
8076 memset(utf8buf, 0x1, 1000);
8077 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8079 CHECK_EQ(5, charlen);
8080 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8082 memset(utf8buf, 0x1, 1000);
8083 len = str2->WriteUtf8(utf8buf, 8, &charlen);
8085 CHECK_EQ(5, charlen);
8086 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9));
8088 memset(utf8buf, 0x1, 1000);
8089 len = str2->WriteUtf8(utf8buf, 7, &charlen);
8091 CHECK_EQ(4, charlen);
8092 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8094 memset(utf8buf, 0x1, 1000);
8095 len = str2->WriteUtf8(utf8buf, 6, &charlen);
8097 CHECK_EQ(4, charlen);
8098 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8100 memset(utf8buf, 0x1, 1000);
8101 len = str2->WriteUtf8(utf8buf, 5, &charlen);
8103 CHECK_EQ(4, charlen);
8104 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5));
8106 memset(utf8buf, 0x1, 1000);
8107 len = str2->WriteUtf8(utf8buf, 4, &charlen);
8109 CHECK_EQ(3, charlen);
8110 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8112 memset(utf8buf, 0x1, 1000);
8113 len = str2->WriteUtf8(utf8buf, 3, &charlen);
8115 CHECK_EQ(3, charlen);
8116 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4));
8118 memset(utf8buf, 0x1, 1000);
8119 len = str2->WriteUtf8(utf8buf, 2, &charlen);
8121 CHECK_EQ(2, charlen);
8122 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3));
8124 // allow orphan surrogates by default
8125 memset(utf8buf, 0x1, 1000);
8126 len = orphans_str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen);
8128 CHECK_EQ(8, charlen);
8129 CHECK_EQ(0, strcmp(utf8buf, "ab\355\240\200cd\355\260\200ef"));
8131 // replace orphan surrogates with unicode replacement character
8132 memset(utf8buf, 0x1, 1000);
8133 len = orphans_str->WriteUtf8(utf8buf,
8136 String::REPLACE_INVALID_UTF8);
8138 CHECK_EQ(8, charlen);
8139 CHECK_EQ(0, strcmp(utf8buf, "ab\357\277\275cd\357\277\275ef"));
8141 // replace single lead surrogate with unicode replacement character
8142 memset(utf8buf, 0x1, 1000);
8143 len = lead_str->WriteUtf8(utf8buf,
8146 String::REPLACE_INVALID_UTF8);
8148 CHECK_EQ(1, charlen);
8149 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8151 // replace single trail surrogate with unicode replacement character
8152 memset(utf8buf, 0x1, 1000);
8153 len = trail_str->WriteUtf8(utf8buf,
8156 String::REPLACE_INVALID_UTF8);
8158 CHECK_EQ(1, charlen);
8159 CHECK_EQ(0, strcmp(utf8buf, "\357\277\275"));
8161 // do not replace / write anything if surrogate pair does not fit the buffer
8163 memset(utf8buf, 0x1, 1000);
8164 len = pair_str->WriteUtf8(utf8buf,
8167 String::REPLACE_INVALID_UTF8);
8169 CHECK_EQ(0, charlen);
8171 memset(utf8buf, 0x1, sizeof(utf8buf));
8172 len = GetUtf8Length(left_tree);
8174 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride;
8175 CHECK_EQ(utf8_expected, len);
8176 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8177 CHECK_EQ(utf8_expected, len);
8178 CHECK_EQ(0xd800 / kStride, charlen);
8179 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3]));
8180 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2]));
8181 CHECK_EQ(0xc0 - kStride,
8182 static_cast<unsigned char>(utf8buf[utf8_expected - 1]));
8183 CHECK_EQ(1, utf8buf[utf8_expected]);
8185 memset(utf8buf, 0x1, sizeof(utf8buf));
8186 len = GetUtf8Length(right_tree);
8187 CHECK_EQ(utf8_expected, len);
8188 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen);
8189 CHECK_EQ(utf8_expected, len);
8190 CHECK_EQ(0xd800 / kStride, charlen);
8191 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0]));
8192 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1]));
8193 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2]));
8194 CHECK_EQ(1, utf8buf[utf8_expected]);
8196 memset(buf, 0x1, sizeof(buf));
8197 memset(wbuf, 0x1, sizeof(wbuf));
8198 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8200 len = str->Write(wbuf);
8202 CHECK_EQ(0, strcmp("abcde", buf));
8203 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8204 CHECK_EQ(0, StrCmp16(answer1, wbuf));
8206 memset(buf, 0x1, sizeof(buf));
8207 memset(wbuf, 0x1, sizeof(wbuf));
8208 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4);
8210 len = str->Write(wbuf, 0, 4);
8212 CHECK_EQ(0, strncmp("abcd\1", buf, 5));
8213 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101};
8214 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5));
8216 memset(buf, 0x1, sizeof(buf));
8217 memset(wbuf, 0x1, sizeof(wbuf));
8218 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5);
8220 len = str->Write(wbuf, 0, 5);
8222 CHECK_EQ(0, strncmp("abcde\1", buf, 6));
8223 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101};
8224 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6));
8226 memset(buf, 0x1, sizeof(buf));
8227 memset(wbuf, 0x1, sizeof(wbuf));
8228 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6);
8230 len = str->Write(wbuf, 0, 6);
8232 CHECK_EQ(0, strcmp("abcde", buf));
8233 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8234 CHECK_EQ(0, StrCmp16(answer4, wbuf));
8236 memset(buf, 0x1, sizeof(buf));
8237 memset(wbuf, 0x1, sizeof(wbuf));
8238 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1);
8240 len = str->Write(wbuf, 4, -1);
8242 CHECK_EQ(0, strcmp("e", buf));
8243 uint16_t answer5[] = {'e', '\0'};
8244 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8246 memset(buf, 0x1, sizeof(buf));
8247 memset(wbuf, 0x1, sizeof(wbuf));
8248 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6);
8250 len = str->Write(wbuf, 4, 6);
8252 CHECK_EQ(0, strcmp("e", buf));
8253 CHECK_EQ(0, StrCmp16(answer5, wbuf));
8255 memset(buf, 0x1, sizeof(buf));
8256 memset(wbuf, 0x1, sizeof(wbuf));
8257 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1);
8259 len = str->Write(wbuf, 4, 1);
8261 CHECK_EQ(0, strncmp("e\1", buf, 2));
8262 uint16_t answer6[] = {'e', 0x101};
8263 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2));
8265 memset(buf, 0x1, sizeof(buf));
8266 memset(wbuf, 0x1, sizeof(wbuf));
8267 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1);
8269 len = str->Write(wbuf, 3, 1);
8271 CHECK_EQ(0, strncmp("d\1", buf, 2));
8272 uint16_t answer7[] = {'d', 0x101};
8273 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2));
8275 memset(wbuf, 0x1, sizeof(wbuf));
8277 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION);
8279 CHECK_EQ('X', wbuf[5]);
8280 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'};
8281 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'};
8282 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5));
8283 CHECK_NE(0, StrCmp16(answer8b, wbuf));
8285 CHECK_EQ(0, StrCmp16(answer8b, wbuf));
8287 memset(buf, 0x1, sizeof(buf));
8289 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf),
8292 String::NO_NULL_TERMINATION);
8294 CHECK_EQ('X', buf[5]);
8295 CHECK_EQ(0, strncmp("abcde", buf, 5));
8296 CHECK_NE(0, strcmp("abcde", buf));
8298 CHECK_EQ(0, strcmp("abcde", buf));
8300 memset(utf8buf, 0x1, sizeof(utf8buf));
8302 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8303 String::NO_NULL_TERMINATION);
8305 CHECK_EQ('X', utf8buf[8]);
8306 CHECK_EQ(5, charlen);
8307 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8));
8308 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8310 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203"));
8312 memset(utf8buf, 0x1, sizeof(utf8buf));
8314 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen,
8315 String::NO_NULL_TERMINATION);
8317 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched.
8318 CHECK_EQ(5, charlen);
8320 CHECK_EQ(0, strcmp(utf8buf, "abcde"));
8322 memset(buf, 0x1, sizeof(buf));
8323 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
8325 CHECK_EQ(0, strcmp("abc", buf));
8326 CHECK_EQ(0, buf[3]);
8327 CHECK_EQ(0, strcmp("def", buf + 4));
8329 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION));
8330 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION));
8331 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION));
8335 static void Utf16Helper(
8336 LocalContext& context, // NOLINT
8338 const char* lengths_name,
8340 Local<v8::Array> a =
8341 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8342 Local<v8::Array> alens =
8343 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8344 for (int i = 0; i < len; i++) {
8345 Local<v8::String> string =
8346 Local<v8::String>::Cast(a->Get(i));
8347 Local<v8::Number> expected_len =
8348 Local<v8::Number>::Cast(alens->Get(i));
8349 int length = GetUtf8Length(string);
8350 CHECK_EQ(static_cast<int>(expected_len->Value()), length);
8355 static uint16_t StringGet(Handle<String> str, int index) {
8356 i::Handle<i::String> istring =
8357 v8::Utils::OpenHandle(String::Cast(*str));
8358 return istring->Get(index);
8362 static void WriteUtf8Helper(
8363 LocalContext& context, // NOLINT
8365 const char* lengths_name,
8367 Local<v8::Array> b =
8368 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name)));
8369 Local<v8::Array> alens =
8370 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name)));
8373 for (int i = 0; i < len; i++) {
8374 Local<v8::String> string =
8375 Local<v8::String>::Cast(b->Get(i));
8376 Local<v8::Number> expected_len =
8377 Local<v8::Number>::Cast(alens->Get(i));
8378 int utf8_length = static_cast<int>(expected_len->Value());
8379 for (int j = utf8_length + 1; j >= 0; j--) {
8380 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer));
8381 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2));
8384 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS);
8386 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION);
8387 CHECK_GE(utf8_length + 1, utf8_written);
8388 CHECK_GE(utf8_length, utf8_written2);
8389 for (int k = 0; k < utf8_written2; k++) {
8390 CHECK_EQ(buffer[k], buffer2[k]);
8392 CHECK(nchars * 3 >= utf8_written - 1);
8393 CHECK(nchars <= utf8_written);
8394 if (j == utf8_length + 1) {
8395 CHECK_EQ(utf8_written2, utf8_length);
8396 CHECK_EQ(utf8_written2 + 1, utf8_written);
8398 CHECK_EQ(buffer[utf8_written], 42);
8399 if (j > utf8_length) {
8400 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0);
8401 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42);
8402 Handle<String> roundtrip = v8_str(buffer);
8403 CHECK(roundtrip->Equals(string));
8405 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8407 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42);
8409 uint16_t trail = StringGet(string, nchars - 1);
8410 uint16_t lead = StringGet(string, nchars - 2);
8411 if (((lead & 0xfc00) == 0xd800) &&
8412 ((trail & 0xfc00) == 0xdc00)) {
8413 unsigned char u1 = buffer2[utf8_written2 - 4];
8414 unsigned char u2 = buffer2[utf8_written2 - 3];
8415 unsigned char u3 = buffer2[utf8_written2 - 2];
8416 unsigned char u4 = buffer2[utf8_written2 - 1];
8417 CHECK_EQ((u1 & 0xf8), 0xf0);
8418 CHECK_EQ((u2 & 0xc0), 0x80);
8419 CHECK_EQ((u3 & 0xc0), 0x80);
8420 CHECK_EQ((u4 & 0xc0), 0x80);
8421 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff);
8422 CHECK_EQ((u4 & 0x3f), (c & 0x3f));
8423 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f));
8424 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f));
8425 CHECK_EQ((u1 & 0x3), c >> 18);
8433 THREADED_TEST(Utf16) {
8434 LocalContext context;
8435 v8::HandleScope scope(context->GetIsolate());
8437 "var pad = '01234567890123456789';"
8439 "var plens = [20, 3, 3];"
8440 "p.push('01234567890123456789');"
8441 "var lead = 0xd800;"
8442 "var trail = 0xdc00;"
8443 "p.push(String.fromCharCode(0xd800));"
8444 "p.push(String.fromCharCode(0xdc00));"
8449 "for (var i = 0; i < 3; i++) {"
8450 " p[1] = String.fromCharCode(lead++);"
8451 " for (var j = 0; j < 3; j++) {"
8452 " p[2] = String.fromCharCode(trail++);"
8453 " a.push(p[i] + p[j]);"
8454 " b.push(p[i] + p[j]);"
8455 " c.push(p[i] + p[j]);"
8456 " alens.push(plens[i] + plens[j]);"
8459 "alens[5] -= 2;" // Here the surrogate pairs match up.
8464 "for (var m = 0; m < 9; m++) {"
8465 " for (var n = 0; n < 9; n++) {"
8466 " a2.push(a[m] + a[n]);"
8467 " b2.push(b[m] + b[n]);"
8468 " var newc = 'x' + c[m] + c[n] + 'y';"
8469 " c2.push(newc.substring(1, newc.length - 1));"
8470 " var utf = alens[m] + alens[n];" // And here.
8471 // The 'n's that start with 0xdc.. are 6-8
8472 // The 'm's that end with 0xd8.. are 1, 4 and 7
8473 " if ((m % 3) == 1 && n >= 6) utf -= 2;"
8474 " a2lens.push(utf);"
8477 Utf16Helper(context, "a", "alens", 9);
8478 Utf16Helper(context, "a2", "a2lens", 81);
8479 WriteUtf8Helper(context, "b", "alens", 9);
8480 WriteUtf8Helper(context, "b2", "a2lens", 81);
8481 WriteUtf8Helper(context, "c2", "a2lens", 81);
8485 static bool SameSymbol(Handle<String> s1, Handle<String> s2) {
8486 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1));
8487 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2));
8488 return *is1 == *is2;
8491 static void SameSymbolHelper(v8::Isolate* isolate, const char* a,
8493 Handle<String> symbol1 =
8494 v8::String::NewFromUtf8(isolate, a, v8::String::kInternalizedString);
8495 Handle<String> symbol2 =
8496 v8::String::NewFromUtf8(isolate, b, v8::String::kInternalizedString);
8497 CHECK(SameSymbol(symbol1, symbol2));
8501 THREADED_TEST(Utf16Symbol) {
8502 LocalContext context;
8503 v8::HandleScope scope(context->GetIsolate());
8505 Handle<String> symbol1 = v8::String::NewFromUtf8(
8506 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8507 Handle<String> symbol2 = v8::String::NewFromUtf8(
8508 context->GetIsolate(), "abc", v8::String::kInternalizedString);
8509 CHECK(SameSymbol(symbol1, symbol2));
8511 SameSymbolHelper(context->GetIsolate(),
8512 "\360\220\220\205", // 4 byte encoding.
8513 "\355\240\201\355\260\205"); // 2 3-byte surrogates.
8514 SameSymbolHelper(context->GetIsolate(),
8515 "\355\240\201\355\260\206", // 2 3-byte surrogates.
8516 "\360\220\220\206"); // 4 byte encoding.
8517 SameSymbolHelper(context->GetIsolate(),
8518 "x\360\220\220\205", // 4 byte encoding.
8519 "x\355\240\201\355\260\205"); // 2 3-byte surrogates.
8520 SameSymbolHelper(context->GetIsolate(),
8521 "x\355\240\201\355\260\206", // 2 3-byte surrogates.
8522 "x\360\220\220\206"); // 4 byte encoding.
8524 "var sym0 = 'benedictus';"
8525 "var sym0b = 'S\303\270ren';"
8526 "var sym1 = '\355\240\201\355\260\207';"
8527 "var sym2 = '\360\220\220\210';"
8528 "var sym3 = 'x\355\240\201\355\260\207';"
8529 "var sym4 = 'x\360\220\220\210';"
8530 "if (sym1.length != 2) throw sym1;"
8531 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);"
8532 "if (sym2.length != 2) throw sym2;"
8533 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);"
8534 "if (sym3.length != 3) throw sym3;"
8535 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);"
8536 "if (sym4.length != 3) throw sym4;"
8537 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);");
8538 Handle<String> sym0 = v8::String::NewFromUtf8(
8539 context->GetIsolate(), "benedictus", v8::String::kInternalizedString);
8540 Handle<String> sym0b = v8::String::NewFromUtf8(
8541 context->GetIsolate(), "S\303\270ren", v8::String::kInternalizedString);
8542 Handle<String> sym1 =
8543 v8::String::NewFromUtf8(context->GetIsolate(), "\355\240\201\355\260\207",
8544 v8::String::kInternalizedString);
8545 Handle<String> sym2 =
8546 v8::String::NewFromUtf8(context->GetIsolate(), "\360\220\220\210",
8547 v8::String::kInternalizedString);
8548 Handle<String> sym3 = v8::String::NewFromUtf8(
8549 context->GetIsolate(), "x\355\240\201\355\260\207",
8550 v8::String::kInternalizedString);
8551 Handle<String> sym4 =
8552 v8::String::NewFromUtf8(context->GetIsolate(), "x\360\220\220\210",
8553 v8::String::kInternalizedString);
8554 v8::Local<v8::Object> global = context->Global();
8555 Local<Value> s0 = global->Get(v8_str("sym0"));
8556 Local<Value> s0b = global->Get(v8_str("sym0b"));
8557 Local<Value> s1 = global->Get(v8_str("sym1"));
8558 Local<Value> s2 = global->Get(v8_str("sym2"));
8559 Local<Value> s3 = global->Get(v8_str("sym3"));
8560 Local<Value> s4 = global->Get(v8_str("sym4"));
8561 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0)));
8562 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b)));
8563 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1)));
8564 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2)));
8565 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3)));
8566 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4)));
8570 THREADED_TEST(ToArrayIndex) {
8571 LocalContext context;
8572 v8::Isolate* isolate = context->GetIsolate();
8573 v8::HandleScope scope(isolate);
8575 v8::Handle<String> str = v8_str("42");
8576 v8::Handle<v8::Uint32> index = str->ToArrayIndex();
8577 CHECK(!index.IsEmpty());
8578 CHECK_EQ(42.0, index->Uint32Value());
8579 str = v8_str("42asdf");
8580 index = str->ToArrayIndex();
8581 CHECK(index.IsEmpty());
8582 str = v8_str("-42");
8583 index = str->ToArrayIndex();
8584 CHECK(index.IsEmpty());
8585 str = v8_str("4294967295");
8586 index = str->ToArrayIndex();
8587 CHECK(!index.IsEmpty());
8588 CHECK_EQ(4294967295.0, index->Uint32Value());
8589 v8::Handle<v8::Number> num = v8::Number::New(isolate, 1);
8590 index = num->ToArrayIndex();
8591 CHECK(!index.IsEmpty());
8592 CHECK_EQ(1.0, index->Uint32Value());
8593 num = v8::Number::New(isolate, -1);
8594 index = num->ToArrayIndex();
8595 CHECK(index.IsEmpty());
8596 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
8597 index = obj->ToArrayIndex();
8598 CHECK(index.IsEmpty());
8602 THREADED_TEST(ErrorConstruction) {
8603 LocalContext context;
8604 v8::HandleScope scope(context->GetIsolate());
8606 v8::Handle<String> foo = v8_str("foo");
8607 v8::Handle<String> message = v8_str("message");
8608 v8::Handle<Value> range_error = v8::Exception::RangeError(foo);
8609 CHECK(range_error->IsObject());
8610 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo));
8611 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo);
8612 CHECK(reference_error->IsObject());
8613 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo));
8614 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo);
8615 CHECK(syntax_error->IsObject());
8616 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo));
8617 v8::Handle<Value> type_error = v8::Exception::TypeError(foo);
8618 CHECK(type_error->IsObject());
8619 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo));
8620 v8::Handle<Value> error = v8::Exception::Error(foo);
8621 CHECK(error->IsObject());
8622 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8626 static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
8627 ApiTestFuzzer::Fuzz();
8628 v8::Handle<String> foo = v8_str("foo");
8629 v8::Handle<String> message = v8_str("message");
8630 v8::Handle<Value> error = v8::Exception::Error(foo);
8631 CHECK(error->IsObject());
8632 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
8633 info.GetIsolate()->ThrowException(error);
8634 info.GetReturnValue().SetUndefined();
8638 THREADED_TEST(ExceptionGetMessage) {
8639 LocalContext context;
8640 v8::HandleScope scope(context->GetIsolate());
8641 v8::Handle<String> foo_str = v8_str("foo");
8642 v8::Handle<String> message_str = v8_str("message");
8644 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
8646 Local<v8::FunctionTemplate> fun =
8647 v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
8648 v8::Local<v8::Object> global = context->Global();
8649 global->Set(v8_str("throwV8Exception"), fun->GetFunction());
8654 " throwV8Exception();\n"
8657 CHECK(try_catch.HasCaught());
8659 v8::Handle<v8::Value> error = try_catch.Exception();
8660 CHECK(error->IsObject());
8661 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
8663 v8::Handle<v8::Message> message = v8::Exception::GetMessage(error);
8664 CHECK(!message.IsEmpty());
8665 CHECK_EQ(2, message->GetLineNumber());
8666 CHECK_EQ(2, message->GetStartColumn());
8668 v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
8669 CHECK(!stackTrace.IsEmpty());
8670 CHECK_EQ(2, stackTrace->GetFrameCount());
8672 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
8674 // Now check message location when SetCaptureStackTraceForUncaughtExceptions
8680 " return throwV8Exception();\n"
8683 CHECK(try_catch.HasCaught());
8685 error = try_catch.Exception();
8686 CHECK(error->IsObject());
8687 CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
8689 message = v8::Exception::GetMessage(error);
8690 CHECK(!message.IsEmpty());
8691 CHECK_EQ(2, message->GetLineNumber());
8692 CHECK_EQ(9, message->GetStartColumn());
8694 // Should be empty stack trace.
8695 stackTrace = message->GetStackTrace();
8696 CHECK(stackTrace.IsEmpty());
8700 static void YGetter(Local<String> name,
8701 const v8::PropertyCallbackInfo<v8::Value>& info) {
8702 ApiTestFuzzer::Fuzz();
8703 info.GetReturnValue().Set(v8_num(10));
8707 static void YSetter(Local<String> name,
8709 const v8::PropertyCallbackInfo<void>& info) {
8710 Local<Object> this_obj = Local<Object>::Cast(info.This());
8711 if (this_obj->Has(name)) this_obj->Delete(name);
8712 this_obj->Set(name, value);
8716 THREADED_TEST(DeleteAccessor) {
8717 v8::Isolate* isolate = CcTest::isolate();
8718 v8::HandleScope scope(isolate);
8719 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
8720 obj->SetAccessor(v8_str("y"), YGetter, YSetter);
8721 LocalContext context;
8722 v8::Handle<v8::Object> holder = obj->NewInstance();
8723 context->Global()->Set(v8_str("holder"), holder);
8724 v8::Handle<Value> result = CompileRun(
8725 "holder.y = 11; holder.y = 12; holder.y");
8726 CHECK_EQ(12, result->Uint32Value());
8730 THREADED_TEST(TypeSwitch) {
8731 v8::Isolate* isolate = CcTest::isolate();
8732 v8::HandleScope scope(isolate);
8733 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(isolate);
8734 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(isolate);
8735 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(isolate);
8736 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 };
8737 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs);
8738 LocalContext context;
8739 v8::Handle<v8::Object> obj0 = v8::Object::New(isolate);
8740 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance();
8741 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance();
8742 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance();
8743 for (int i = 0; i < 10; i++) {
8744 CHECK_EQ(0, type_switch->match(obj0));
8745 CHECK_EQ(1, type_switch->match(obj1));
8746 CHECK_EQ(2, type_switch->match(obj2));
8747 CHECK_EQ(3, type_switch->match(obj3));
8748 CHECK_EQ(3, type_switch->match(obj3));
8749 CHECK_EQ(2, type_switch->match(obj2));
8750 CHECK_EQ(1, type_switch->match(obj1));
8751 CHECK_EQ(0, type_switch->match(obj0));
8756 static int trouble_nesting = 0;
8757 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
8758 ApiTestFuzzer::Fuzz();
8761 // Call a JS function that throws an uncaught exception.
8762 Local<v8::Object> arg_this =
8763 args.GetIsolate()->GetCurrentContext()->Global();
8764 Local<Value> trouble_callee = (trouble_nesting == 3) ?
8765 arg_this->Get(v8_str("trouble_callee")) :
8766 arg_this->Get(v8_str("trouble_caller"));
8767 CHECK(trouble_callee->IsFunction());
8768 args.GetReturnValue().Set(
8769 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL));
8773 static int report_count = 0;
8774 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>,
8775 v8::Handle<Value>) {
8780 // Counts uncaught exceptions, but other tests running in parallel
8781 // also have uncaught exceptions.
8782 TEST(ApiUncaughtException) {
8785 v8::Isolate* isolate = env->GetIsolate();
8786 v8::HandleScope scope(isolate);
8787 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
8789 Local<v8::FunctionTemplate> fun =
8790 v8::FunctionTemplate::New(isolate, TroubleCallback);
8791 v8::Local<v8::Object> global = env->Global();
8792 global->Set(v8_str("trouble"), fun->GetFunction());
8795 "function trouble_callee() {"
8799 "function trouble_caller() {"
8802 Local<Value> trouble = global->Get(v8_str("trouble"));
8803 CHECK(trouble->IsFunction());
8804 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee"));
8805 CHECK(trouble_callee->IsFunction());
8806 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller"));
8807 CHECK(trouble_caller->IsFunction());
8808 Function::Cast(*trouble_caller)->Call(global, 0, NULL);
8809 CHECK_EQ(1, report_count);
8810 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
8813 static const char* script_resource_name = "ExceptionInNativeScript.js";
8814 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
8815 v8::Handle<Value>) {
8816 v8::Handle<v8::Value> name_val = message->GetScriptOrigin().ResourceName();
8817 CHECK(!name_val.IsEmpty() && name_val->IsString());
8818 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
8819 CHECK_EQ(script_resource_name, *name);
8820 CHECK_EQ(3, message->GetLineNumber());
8821 v8::String::Utf8Value source_line(message->GetSourceLine());
8822 CHECK_EQ(" new o.foo();", *source_line);
8826 TEST(ExceptionInNativeScript) {
8828 v8::Isolate* isolate = env->GetIsolate();
8829 v8::HandleScope scope(isolate);
8830 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener);
8832 Local<v8::FunctionTemplate> fun =
8833 v8::FunctionTemplate::New(isolate, TroubleCallback);
8834 v8::Local<v8::Object> global = env->Global();
8835 global->Set(v8_str("trouble"), fun->GetFunction());
8837 CompileRunWithOrigin(
8838 "function trouble() {\n"
8842 script_resource_name);
8843 Local<Value> trouble = global->Get(v8_str("trouble"));
8844 CHECK(trouble->IsFunction());
8845 Function::Cast(*trouble)->Call(global, 0, NULL);
8846 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener);
8850 TEST(CompilationErrorUsingTryCatchHandler) {
8852 v8::HandleScope scope(env->GetIsolate());
8853 v8::TryCatch try_catch;
8854 v8_compile("This doesn't &*&@#$&*^ compile.");
8855 CHECK_NE(NULL, *try_catch.Exception());
8856 CHECK(try_catch.HasCaught());
8860 TEST(TryCatchFinallyUsingTryCatchHandler) {
8862 v8::HandleScope scope(env->GetIsolate());
8863 v8::TryCatch try_catch;
8864 CompileRun("try { throw ''; } catch (e) {}");
8865 CHECK(!try_catch.HasCaught());
8866 CompileRun("try { throw ''; } finally {}");
8867 CHECK(try_catch.HasCaught());
8871 "try { throw ''; } finally { return; }"
8873 CHECK(!try_catch.HasCaught());
8876 " { try { throw ''; } finally { throw 0; }"
8878 CHECK(try_catch.HasCaught());
8882 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
8883 v8::HandleScope scope(args.GetIsolate());
8884 CompileRun(args[0]->ToString());
8888 TEST(TryCatchFinallyStoresMessageUsingTryCatchHandler) {
8889 v8::Isolate* isolate = CcTest::isolate();
8890 v8::HandleScope scope(isolate);
8891 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
8892 templ->Set(v8_str("CEvaluate"),
8893 v8::FunctionTemplate::New(isolate, CEvaluate));
8894 LocalContext context(0, templ);
8895 v8::TryCatch try_catch;
8897 " CEvaluate('throw 1;');"
8900 CHECK(try_catch.HasCaught());
8901 CHECK(!try_catch.Message().IsEmpty());
8902 String::Utf8Value exception_value(try_catch.Exception());
8903 CHECK_EQ(*exception_value, "1");
8906 " CEvaluate('throw 1;');"
8910 CHECK(try_catch.HasCaught());
8911 CHECK(!try_catch.Message().IsEmpty());
8912 String::Utf8Value finally_exception_value(try_catch.Exception());
8913 CHECK_EQ(*finally_exception_value, "2");
8917 // For use within the TestSecurityHandler() test.
8918 static bool g_security_callback_result = false;
8919 static bool NamedSecurityTestCallback(Local<v8::Object> global,
8921 v8::AccessType type,
8922 Local<Value> data) {
8924 // Always allow read access.
8925 if (type == v8::ACCESS_GET)
8928 // Sometimes allow other access.
8929 return g_security_callback_result;
8933 static bool IndexedSecurityTestCallback(Local<v8::Object> global,
8935 v8::AccessType type,
8936 Local<Value> data) {
8938 // Always allow read access.
8939 if (type == v8::ACCESS_GET)
8942 // Sometimes allow other access.
8943 return g_security_callback_result;
8947 // SecurityHandler can't be run twice
8948 TEST(SecurityHandler) {
8949 v8::Isolate* isolate = CcTest::isolate();
8950 v8::HandleScope scope0(isolate);
8951 v8::Handle<v8::ObjectTemplate> global_template =
8952 v8::ObjectTemplate::New(isolate);
8953 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback,
8954 IndexedSecurityTestCallback);
8955 // Create an environment
8956 v8::Handle<Context> context0 = Context::New(isolate, NULL, global_template);
8959 v8::Handle<v8::Object> global0 = context0->Global();
8960 v8::Handle<Script> script0 = v8_compile("foo = 111");
8962 global0->Set(v8_str("0"), v8_num(999));
8963 v8::Handle<Value> foo0 = global0->Get(v8_str("foo"));
8964 CHECK_EQ(111, foo0->Int32Value());
8965 v8::Handle<Value> z0 = global0->Get(v8_str("0"));
8966 CHECK_EQ(999, z0->Int32Value());
8968 // Create another environment, should fail security checks.
8969 v8::HandleScope scope1(isolate);
8971 v8::Handle<Context> context1 =
8972 Context::New(isolate, NULL, global_template);
8975 v8::Handle<v8::Object> global1 = context1->Global();
8976 global1->Set(v8_str("othercontext"), global0);
8977 // This set will fail the security check.
8978 v8::Handle<Script> script1 =
8979 v8_compile("othercontext.foo = 222; othercontext[0] = 888;");
8981 // This read will pass the security check.
8982 v8::Handle<Value> foo1 = global0->Get(v8_str("foo"));
8983 CHECK_EQ(111, foo1->Int32Value());
8984 // This read will pass the security check.
8985 v8::Handle<Value> z1 = global0->Get(v8_str("0"));
8986 CHECK_EQ(999, z1->Int32Value());
8988 // Create another environment, should pass security checks.
8989 { g_security_callback_result = true; // allow security handler to pass.
8990 v8::HandleScope scope2(isolate);
8991 LocalContext context2;
8992 v8::Handle<v8::Object> global2 = context2->Global();
8993 global2->Set(v8_str("othercontext"), global0);
8994 v8::Handle<Script> script2 =
8995 v8_compile("othercontext.foo = 333; othercontext[0] = 888;");
8997 v8::Handle<Value> foo2 = global0->Get(v8_str("foo"));
8998 CHECK_EQ(333, foo2->Int32Value());
8999 v8::Handle<Value> z2 = global0->Get(v8_str("0"));
9000 CHECK_EQ(888, z2->Int32Value());
9008 THREADED_TEST(SecurityChecks) {
9010 v8::HandleScope handle_scope(env1->GetIsolate());
9011 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9013 Local<Value> foo = v8_str("foo");
9014 Local<Value> bar = v8_str("bar");
9016 // Set to the same domain.
9017 env1->SetSecurityToken(foo);
9019 // Create a function in env1.
9020 CompileRun("spy=function(){return spy;}");
9021 Local<Value> spy = env1->Global()->Get(v8_str("spy"));
9022 CHECK(spy->IsFunction());
9024 // Create another function accessing global objects.
9025 CompileRun("spy2=function(){return new this.Array();}");
9026 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2"));
9027 CHECK(spy2->IsFunction());
9029 // Switch to env2 in the same domain and invoke spy on env2.
9031 env2->SetSecurityToken(foo);
9033 Context::Scope scope_env2(env2);
9034 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL);
9035 CHECK(result->IsFunction());
9039 env2->SetSecurityToken(bar);
9040 Context::Scope scope_env2(env2);
9042 // Call cross_domain_call, it should throw an exception
9043 v8::TryCatch try_catch;
9044 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL);
9045 CHECK(try_catch.HasCaught());
9050 // Regression test case for issue 1183439.
9051 THREADED_TEST(SecurityChecksForPrototypeChain) {
9052 LocalContext current;
9053 v8::HandleScope scope(current->GetIsolate());
9054 v8::Handle<Context> other = Context::New(current->GetIsolate());
9056 // Change context to be able to get to the Object function in the
9057 // other context without hitting the security checks.
9058 v8::Local<Value> other_object;
9059 { Context::Scope scope(other);
9060 other_object = other->Global()->Get(v8_str("Object"));
9061 other->Global()->Set(v8_num(42), v8_num(87));
9064 current->Global()->Set(v8_str("other"), other->Global());
9065 CHECK(v8_compile("other")->Run()->Equals(other->Global()));
9067 // Make sure the security check fails here and we get an undefined
9068 // result instead of getting the Object function. Repeat in a loop
9069 // to make sure to exercise the IC code.
9070 v8::Local<Script> access_other0 = v8_compile("other.Object");
9071 v8::Local<Script> access_other1 = v8_compile("other[42]");
9072 for (int i = 0; i < 5; i++) {
9073 CHECK(access_other0->Run().IsEmpty());
9074 CHECK(access_other1->Run().IsEmpty());
9077 // Create an object that has 'other' in its prototype chain and make
9078 // sure we cannot access the Object function indirectly through
9079 // that. Repeat in a loop to make sure to exercise the IC code.
9080 v8_compile("function F() { };"
9081 "F.prototype = other;"
9082 "var f = new F();")->Run();
9083 v8::Local<Script> access_f0 = v8_compile("f.Object");
9084 v8::Local<Script> access_f1 = v8_compile("f[42]");
9085 for (int j = 0; j < 5; j++) {
9086 CHECK(access_f0->Run().IsEmpty());
9087 CHECK(access_f1->Run().IsEmpty());
9090 // Now it gets hairy: Set the prototype for the other global object
9091 // to be the current global object. The prototype chain for 'f' now
9092 // goes through 'other' but ends up in the current global object.
9093 { Context::Scope scope(other);
9094 other->Global()->Set(v8_str("__proto__"), current->Global());
9096 // Set a named and an index property on the current global
9097 // object. To force the lookup to go through the other global object,
9098 // the properties must not exist in the other global object.
9099 current->Global()->Set(v8_str("foo"), v8_num(100));
9100 current->Global()->Set(v8_num(99), v8_num(101));
9101 // Try to read the properties from f and make sure that the access
9102 // gets stopped by the security checks on the other global object.
9103 Local<Script> access_f2 = v8_compile("f.foo");
9104 Local<Script> access_f3 = v8_compile("f[99]");
9105 for (int k = 0; k < 5; k++) {
9106 CHECK(access_f2->Run().IsEmpty());
9107 CHECK(access_f3->Run().IsEmpty());
9112 static bool named_security_check_with_gc_called;
9114 static bool NamedSecurityCallbackWithGC(Local<v8::Object> global,
9116 v8::AccessType type,
9117 Local<Value> data) {
9118 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
9119 named_security_check_with_gc_called = true;
9124 static bool indexed_security_check_with_gc_called;
9126 static bool IndexedSecurityTestCallbackWithGC(Local<v8::Object> global,
9128 v8::AccessType type,
9129 Local<Value> data) {
9130 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
9131 indexed_security_check_with_gc_called = true;
9136 TEST(SecurityTestGCAllowed) {
9137 v8::Isolate* isolate = CcTest::isolate();
9138 v8::HandleScope handle_scope(isolate);
9139 v8::Handle<v8::ObjectTemplate> object_template =
9140 v8::ObjectTemplate::New(isolate);
9141 object_template->SetAccessCheckCallbacks(NamedSecurityCallbackWithGC,
9142 IndexedSecurityTestCallbackWithGC);
9144 v8::Handle<Context> context = Context::New(isolate);
9145 v8::Context::Scope context_scope(context);
9147 context->Global()->Set(v8_str("obj"), object_template->NewInstance());
9149 named_security_check_with_gc_called = false;
9150 CompileRun("obj.foo = new String(1001);");
9151 CHECK(named_security_check_with_gc_called);
9153 indexed_security_check_with_gc_called = false;
9154 CompileRun("obj[0] = new String(1002);");
9155 CHECK(indexed_security_check_with_gc_called);
9157 named_security_check_with_gc_called = false;
9158 CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
9159 CHECK(named_security_check_with_gc_called);
9161 indexed_security_check_with_gc_called = false;
9162 CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
9163 CHECK(indexed_security_check_with_gc_called);
9167 THREADED_TEST(CrossDomainDelete) {
9169 v8::HandleScope handle_scope(env1->GetIsolate());
9170 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9172 Local<Value> foo = v8_str("foo");
9173 Local<Value> bar = v8_str("bar");
9175 // Set to the same domain.
9176 env1->SetSecurityToken(foo);
9177 env2->SetSecurityToken(foo);
9179 env1->Global()->Set(v8_str("prop"), v8_num(3));
9180 env2->Global()->Set(v8_str("env1"), env1->Global());
9182 // Change env2 to a different domain and delete env1.prop.
9183 env2->SetSecurityToken(bar);
9185 Context::Scope scope_env2(env2);
9186 Local<Value> result =
9187 CompileRun("delete env1.prop");
9188 CHECK(result.IsEmpty());
9191 // Check that env1.prop still exists.
9192 Local<Value> v = env1->Global()->Get(v8_str("prop"));
9193 CHECK(v->IsNumber());
9194 CHECK_EQ(3, v->Int32Value());
9198 THREADED_TEST(CrossDomainIsPropertyEnumerable) {
9200 v8::HandleScope handle_scope(env1->GetIsolate());
9201 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9203 Local<Value> foo = v8_str("foo");
9204 Local<Value> bar = v8_str("bar");
9206 // Set to the same domain.
9207 env1->SetSecurityToken(foo);
9208 env2->SetSecurityToken(foo);
9210 env1->Global()->Set(v8_str("prop"), v8_num(3));
9211 env2->Global()->Set(v8_str("env1"), env1->Global());
9213 // env1.prop is enumerable in env2.
9214 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')");
9216 Context::Scope scope_env2(env2);
9217 Local<Value> result = CompileRun(test);
9218 CHECK(result->IsTrue());
9221 // Change env2 to a different domain and test again.
9222 env2->SetSecurityToken(bar);
9224 Context::Scope scope_env2(env2);
9225 Local<Value> result = CompileRun(test);
9226 CHECK(result.IsEmpty());
9231 THREADED_TEST(CrossDomainForIn) {
9233 v8::HandleScope handle_scope(env1->GetIsolate());
9234 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9236 Local<Value> foo = v8_str("foo");
9237 Local<Value> bar = v8_str("bar");
9239 // Set to the same domain.
9240 env1->SetSecurityToken(foo);
9241 env2->SetSecurityToken(foo);
9243 env1->Global()->Set(v8_str("prop"), v8_num(3));
9244 env2->Global()->Set(v8_str("env1"), env1->Global());
9246 // Change env2 to a different domain and set env1's global object
9247 // as the __proto__ of an object in env2 and enumerate properties
9248 // in for-in. It shouldn't enumerate properties on env1's global
9250 env2->SetSecurityToken(bar);
9252 Context::Scope scope_env2(env2);
9253 Local<Value> result = CompileRun(
9255 " var obj = { '__proto__': env1 };"
9257 " for (var p in obj) {"
9258 " if (p == 'prop') return false;"
9265 CHECK(result->IsTrue());
9270 TEST(ContextDetachGlobal) {
9272 v8::HandleScope handle_scope(env1->GetIsolate());
9273 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9275 Local<v8::Object> global1 = env1->Global();
9277 Local<Value> foo = v8_str("foo");
9279 // Set to the same domain.
9280 env1->SetSecurityToken(foo);
9281 env2->SetSecurityToken(foo);
9286 // Create a function in env2 and add a reference to it in env1.
9287 Local<v8::Object> global2 = env2->Global();
9288 global2->Set(v8_str("prop"), v8::Integer::New(env2->GetIsolate(), 1));
9289 CompileRun("function getProp() {return prop;}");
9291 env1->Global()->Set(v8_str("getProp"),
9292 global2->Get(v8_str("getProp")));
9294 // Detach env2's global, and reuse the global object of env2
9296 env2->DetachGlobal();
9298 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9300 v8::Handle<v8::ObjectTemplate>(),
9302 env3->SetSecurityToken(v8_str("bar"));
9305 Local<v8::Object> global3 = env3->Global();
9306 CHECK_EQ(global2, global3);
9307 CHECK(global3->Get(v8_str("prop"))->IsUndefined());
9308 CHECK(global3->Get(v8_str("getProp"))->IsUndefined());
9309 global3->Set(v8_str("prop"), v8::Integer::New(env3->GetIsolate(), -1));
9310 global3->Set(v8_str("prop2"), v8::Integer::New(env3->GetIsolate(), 2));
9313 // Call getProp in env1, and it should return the value 1
9315 Local<Value> get_prop = global1->Get(v8_str("getProp"));
9316 CHECK(get_prop->IsFunction());
9317 v8::TryCatch try_catch;
9318 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL);
9319 CHECK(!try_catch.HasCaught());
9320 CHECK_EQ(1, r->Int32Value());
9323 // Check that env3 is not accessible from env1
9325 Local<Value> r = global3->Get(v8_str("prop2"));
9331 TEST(DetachGlobal) {
9333 v8::HandleScope scope(env1->GetIsolate());
9335 // Create second environment.
9336 v8::Handle<Context> env2 = Context::New(env1->GetIsolate());
9338 Local<Value> foo = v8_str("foo");
9340 // Set same security token for env1 and env2.
9341 env1->SetSecurityToken(foo);
9342 env2->SetSecurityToken(foo);
9344 // Create a property on the global object in env2.
9346 v8::Context::Scope scope(env2);
9347 env2->Global()->Set(v8_str("p"), v8::Integer::New(env2->GetIsolate(), 42));
9350 // Create a reference to env2 global from env1 global.
9351 env1->Global()->Set(v8_str("other"), env2->Global());
9353 // Check that we have access to other.p in env2 from env1.
9354 Local<Value> result = CompileRun("other.p");
9355 CHECK(result->IsInt32());
9356 CHECK_EQ(42, result->Int32Value());
9358 // Hold on to global from env2 and detach global from env2.
9359 Local<v8::Object> global2 = env2->Global();
9360 env2->DetachGlobal();
9362 // Check that the global has been detached. No other.p property can
9364 result = CompileRun("other.p");
9365 CHECK(result.IsEmpty());
9367 // Reuse global2 for env3.
9368 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(),
9370 v8::Handle<v8::ObjectTemplate>(),
9372 CHECK_EQ(global2, env3->Global());
9374 // Start by using the same security token for env3 as for env1 and env2.
9375 env3->SetSecurityToken(foo);
9377 // Create a property on the global object in env3.
9379 v8::Context::Scope scope(env3);
9380 env3->Global()->Set(v8_str("p"), v8::Integer::New(env3->GetIsolate(), 24));
9383 // Check that other.p is now the property in env3 and that we have access.
9384 result = CompileRun("other.p");
9385 CHECK(result->IsInt32());
9386 CHECK_EQ(24, result->Int32Value());
9388 // Change security token for env3 to something different from env1 and env2.
9389 env3->SetSecurityToken(v8_str("bar"));
9391 // Check that we do not have access to other.p in env1. |other| is now
9392 // the global object for env3 which has a different security token,
9393 // so access should be blocked.
9394 result = CompileRun("other.p");
9395 CHECK(result.IsEmpty());
9399 void GetThisX(const v8::FunctionCallbackInfo<v8::Value>& info) {
9400 info.GetReturnValue().Set(
9401 info.GetIsolate()->GetCurrentContext()->Global()->Get(v8_str("x")));
9405 TEST(DetachedAccesses) {
9407 v8::HandleScope scope(env1->GetIsolate());
9409 // Create second environment.
9410 Local<ObjectTemplate> inner_global_template =
9411 FunctionTemplate::New(env1->GetIsolate())->InstanceTemplate();
9412 inner_global_template ->SetAccessorProperty(
9413 v8_str("this_x"), FunctionTemplate::New(env1->GetIsolate(), GetThisX));
9414 v8::Local<Context> env2 =
9415 Context::New(env1->GetIsolate(), NULL, inner_global_template);
9417 Local<Value> foo = v8_str("foo");
9419 // Set same security token for env1 and env2.
9420 env1->SetSecurityToken(foo);
9421 env2->SetSecurityToken(foo);
9423 env1->Global()->Set(v8_str("x"), v8_str("env1_x"));
9426 v8::Context::Scope scope(env2);
9427 env2->Global()->Set(v8_str("x"), v8_str("env2_x"));
9429 "function bound_x() { return x; }"
9430 "function get_x() { return this.x; }"
9431 "function get_x_w() { return (function() {return this.x;})(); }");
9432 env1->Global()->Set(v8_str("bound_x"), CompileRun("bound_x"));
9433 env1->Global()->Set(v8_str("get_x"), CompileRun("get_x"));
9434 env1->Global()->Set(v8_str("get_x_w"), CompileRun("get_x_w"));
9435 env1->Global()->Set(
9437 CompileRun("Object.getOwnPropertyDescriptor(this, 'this_x').get"));
9440 Local<Object> env2_global = env2->Global();
9441 env2_global->TurnOnAccessCheck();
9442 env2->DetachGlobal();
9444 Local<Value> result;
9445 result = CompileRun("bound_x()");
9446 CHECK_EQ(v8_str("env2_x"), result);
9447 result = CompileRun("get_x()");
9448 CHECK(result.IsEmpty());
9449 result = CompileRun("get_x_w()");
9450 CHECK(result.IsEmpty());
9451 result = CompileRun("this_x()");
9452 CHECK_EQ(v8_str("env2_x"), result);
9454 // Reattach env2's proxy
9455 env2 = Context::New(env1->GetIsolate(),
9457 v8::Handle<v8::ObjectTemplate>(),
9459 env2->SetSecurityToken(foo);
9461 v8::Context::Scope scope(env2);
9462 env2->Global()->Set(v8_str("x"), v8_str("env3_x"));
9463 env2->Global()->Set(v8_str("env1"), env1->Global());
9464 result = CompileRun(
9466 "for (var i = 0; i < 4; i++ ) {"
9467 " results.push(env1.bound_x());"
9468 " results.push(env1.get_x());"
9469 " results.push(env1.get_x_w());"
9470 " results.push(env1.this_x());"
9473 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9474 CHECK_EQ(16, results->Length());
9475 for (int i = 0; i < 16; i += 4) {
9476 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9477 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9478 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9479 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9483 result = CompileRun(
9485 "for (var i = 0; i < 4; i++ ) {"
9486 " results.push(bound_x());"
9487 " results.push(get_x());"
9488 " results.push(get_x_w());"
9489 " results.push(this_x());"
9492 Local<v8::Array> results = Local<v8::Array>::Cast(result);
9493 CHECK_EQ(16, results->Length());
9494 for (int i = 0; i < 16; i += 4) {
9495 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9496 CHECK_EQ(v8_str("env3_x"), results->Get(i + 1));
9497 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9498 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9501 result = CompileRun(
9503 "for (var i = 0; i < 4; i++ ) {"
9504 " results.push(this.bound_x());"
9505 " results.push(this.get_x());"
9506 " results.push(this.get_x_w());"
9507 " results.push(this.this_x());"
9510 results = Local<v8::Array>::Cast(result);
9511 CHECK_EQ(16, results->Length());
9512 for (int i = 0; i < 16; i += 4) {
9513 CHECK_EQ(v8_str("env2_x"), results->Get(i + 0));
9514 CHECK_EQ(v8_str("env1_x"), results->Get(i + 1));
9515 CHECK_EQ(v8_str("env3_x"), results->Get(i + 2));
9516 CHECK_EQ(v8_str("env2_x"), results->Get(i + 3));
9521 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false };
9522 static bool NamedAccessBlocker(Local<v8::Object> global,
9524 v8::AccessType type,
9525 Local<Value> data) {
9526 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9527 allowed_access_type[type];
9531 static bool IndexedAccessBlocker(Local<v8::Object> global,
9533 v8::AccessType type,
9534 Local<Value> data) {
9535 return CcTest::isolate()->GetCurrentContext()->Global()->Equals(global) ||
9536 allowed_access_type[type];
9540 static int g_echo_value = -1;
9543 static void EchoGetter(
9545 const v8::PropertyCallbackInfo<v8::Value>& info) {
9546 info.GetReturnValue().Set(v8_num(g_echo_value));
9550 static void EchoSetter(Local<String> name,
9552 const v8::PropertyCallbackInfo<void>&) {
9553 if (value->IsNumber())
9554 g_echo_value = value->Int32Value();
9558 static void UnreachableGetter(
9560 const v8::PropertyCallbackInfo<v8::Value>& info) {
9561 CHECK(false); // This function should not be called..
9565 static void UnreachableSetter(Local<String>,
9567 const v8::PropertyCallbackInfo<void>&) {
9568 CHECK(false); // This function should nto be called.
9572 static void UnreachableFunction(
9573 const v8::FunctionCallbackInfo<v8::Value>& info) {
9574 CHECK(false); // This function should not be called..
9578 TEST(AccessControl) {
9579 v8::Isolate* isolate = CcTest::isolate();
9580 v8::HandleScope handle_scope(isolate);
9581 v8::Handle<v8::ObjectTemplate> global_template =
9582 v8::ObjectTemplate::New(isolate);
9584 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9585 IndexedAccessBlocker);
9587 // Add an accessor accessible by cross-domain JS code.
9588 global_template->SetAccessor(
9589 v8_str("accessible_prop"),
9590 EchoGetter, EchoSetter,
9591 v8::Handle<Value>(),
9592 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9595 // Add an accessor that is not accessible by cross-domain JS code.
9596 global_template->SetAccessor(v8_str("blocked_prop"),
9597 UnreachableGetter, UnreachableSetter,
9598 v8::Handle<Value>(),
9601 global_template->SetAccessorProperty(
9602 v8_str("blocked_js_prop"),
9603 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9604 v8::FunctionTemplate::New(isolate, UnreachableFunction),
9608 // Create an environment
9609 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9612 v8::Handle<v8::Object> global0 = context0->Global();
9614 // Define a property with JS getter and setter.
9616 "function getter() { return 'getter'; };\n"
9617 "function setter() { return 'setter'; }\n"
9618 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})");
9620 Local<Value> getter = global0->Get(v8_str("getter"));
9621 Local<Value> setter = global0->Get(v8_str("setter"));
9623 // And define normal element.
9624 global0->Set(239, v8_str("239"));
9626 // Define an element with JS getter and setter.
9628 "function el_getter() { return 'el_getter'; };\n"
9629 "function el_setter() { return 'el_setter'; };\n"
9630 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});");
9632 Local<Value> el_getter = global0->Get(v8_str("el_getter"));
9633 Local<Value> el_setter = global0->Get(v8_str("el_setter"));
9635 v8::HandleScope scope1(isolate);
9637 v8::Local<Context> context1 = Context::New(isolate);
9640 v8::Handle<v8::Object> global1 = context1->Global();
9641 global1->Set(v8_str("other"), global0);
9643 // Access blocked property.
9644 CompileRun("other.blocked_prop = 1");
9646 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9647 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9650 CompileRun("propertyIsEnumerable.call(other, 'blocked_prop')").IsEmpty());
9652 // Access blocked element.
9653 CHECK(CompileRun("other[239] = 1").IsEmpty());
9655 CHECK(CompileRun("other[239]").IsEmpty());
9656 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239')").IsEmpty());
9657 CHECK(CompileRun("propertyIsEnumerable.call(other, '239')").IsEmpty());
9659 // Enable ACCESS_HAS
9660 allowed_access_type[v8::ACCESS_HAS] = true;
9661 CHECK(CompileRun("other[239]").IsEmpty());
9662 // ... and now we can get the descriptor...
9663 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '239').value")
9665 // ... and enumerate the property.
9666 ExpectTrue("propertyIsEnumerable.call(other, '239')");
9667 allowed_access_type[v8::ACCESS_HAS] = false;
9669 // Access a property with JS accessor.
9670 CHECK(CompileRun("other.js_accessor_p = 2").IsEmpty());
9672 CHECK(CompileRun("other.js_accessor_p").IsEmpty());
9673 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'js_accessor_p')")
9676 // Enable both ACCESS_HAS and ACCESS_GET.
9677 allowed_access_type[v8::ACCESS_HAS] = true;
9678 allowed_access_type[v8::ACCESS_GET] = true;
9680 ExpectString("other.js_accessor_p", "getter");
9682 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter);
9684 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter);
9686 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value");
9688 allowed_access_type[v8::ACCESS_HAS] = false;
9689 allowed_access_type[v8::ACCESS_GET] = false;
9691 // Access an element with JS accessor.
9692 CHECK(CompileRun("other[42] = 2").IsEmpty());
9694 CHECK(CompileRun("other[42]").IsEmpty());
9695 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, '42')").IsEmpty());
9697 // Enable both ACCESS_HAS and ACCESS_GET.
9698 allowed_access_type[v8::ACCESS_HAS] = true;
9699 allowed_access_type[v8::ACCESS_GET] = true;
9701 ExpectString("other[42]", "el_getter");
9702 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter);
9703 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter);
9704 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value");
9706 allowed_access_type[v8::ACCESS_HAS] = false;
9707 allowed_access_type[v8::ACCESS_GET] = false;
9709 v8::Handle<Value> value;
9711 // Access accessible property
9712 value = CompileRun("other.accessible_prop = 3");
9713 CHECK(value->IsNumber());
9714 CHECK_EQ(3, value->Int32Value());
9715 CHECK_EQ(3, g_echo_value);
9717 value = CompileRun("other.accessible_prop");
9718 CHECK(value->IsNumber());
9719 CHECK_EQ(3, value->Int32Value());
9722 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value");
9723 CHECK(value->IsNumber());
9724 CHECK_EQ(3, value->Int32Value());
9726 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')");
9727 CHECK(value->IsTrue());
9729 // Enumeration doesn't enumerate accessors from inaccessible objects in
9730 // the prototype chain even if the accessors are in themselves accessible.
9733 " var obj = { '__proto__': other };"
9735 " for (var p in obj) {"
9736 " if (p == 'accessible_prop' ||"
9737 " p == 'blocked_js_prop' ||"
9738 " p == 'blocked_js_prop') {"
9747 CHECK(value->IsTrue());
9754 TEST(AccessControlES5) {
9755 v8::Isolate* isolate = CcTest::isolate();
9756 v8::HandleScope handle_scope(isolate);
9757 v8::Handle<v8::ObjectTemplate> global_template =
9758 v8::ObjectTemplate::New(isolate);
9760 global_template->SetAccessCheckCallbacks(NamedAccessBlocker,
9761 IndexedAccessBlocker);
9763 // Add accessible accessor.
9764 global_template->SetAccessor(
9765 v8_str("accessible_prop"),
9766 EchoGetter, EchoSetter,
9767 v8::Handle<Value>(),
9768 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE));
9771 // Add an accessor that is not accessible by cross-domain JS code.
9772 global_template->SetAccessor(v8_str("blocked_prop"),
9773 UnreachableGetter, UnreachableSetter,
9774 v8::Handle<Value>(),
9777 // Create an environment
9778 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
9781 v8::Handle<v8::Object> global0 = context0->Global();
9783 v8::Local<Context> context1 = Context::New(isolate);
9785 v8::Handle<v8::Object> global1 = context1->Global();
9786 global1->Set(v8_str("other"), global0);
9788 // Regression test for issue 1154.
9789 CHECK(CompileRun("Object.keys(other)").IsEmpty());
9790 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9792 // Regression test for issue 1027.
9793 CompileRun("Object.defineProperty(\n"
9794 " other, 'blocked_prop', {configurable: false})");
9795 CHECK(CompileRun("other.blocked_prop").IsEmpty());
9796 CHECK(CompileRun("Object.getOwnPropertyDescriptor(other, 'blocked_prop')")
9799 // Regression test for issue 1171.
9800 ExpectTrue("Object.isExtensible(other)");
9801 CompileRun("Object.preventExtensions(other)");
9802 ExpectTrue("Object.isExtensible(other)");
9804 // Object.seal and Object.freeze.
9805 CompileRun("Object.freeze(other)");
9806 ExpectTrue("Object.isExtensible(other)");
9808 CompileRun("Object.seal(other)");
9809 ExpectTrue("Object.isExtensible(other)");
9811 // Regression test for issue 1250.
9812 // Make sure that we can set the accessible accessors value using normal
9814 CompileRun("other.accessible_prop = 42");
9815 CHECK_EQ(42, g_echo_value);
9817 v8::Handle<Value> value;
9818 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})");
9819 value = CompileRun("other.accessible_prop == 42");
9820 CHECK(value->IsTrue());
9824 static bool BlockEverythingNamed(Local<v8::Object> object, Local<Value> name,
9825 v8::AccessType type, Local<Value> data) {
9830 static bool BlockEverythingIndexed(Local<v8::Object> object, uint32_t key,
9831 v8::AccessType type, Local<Value> data) {
9836 THREADED_TEST(AccessControlGetOwnPropertyNames) {
9837 v8::Isolate* isolate = CcTest::isolate();
9838 v8::HandleScope handle_scope(isolate);
9839 v8::Handle<v8::ObjectTemplate> obj_template =
9840 v8::ObjectTemplate::New(isolate);
9842 obj_template->Set(v8_str("x"), v8::Integer::New(isolate, 42));
9843 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9844 BlockEverythingIndexed);
9846 // Create an environment
9847 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template);
9850 v8::Handle<v8::Object> global0 = context0->Global();
9852 v8::HandleScope scope1(CcTest::isolate());
9854 v8::Local<Context> context1 = Context::New(isolate);
9857 v8::Handle<v8::Object> global1 = context1->Global();
9858 global1->Set(v8_str("other"), global0);
9859 global1->Set(v8_str("object"), obj_template->NewInstance());
9861 v8::Handle<Value> value;
9863 // Attempt to get the property names of the other global object and
9864 // of an object that requires access checks. Accessing the other
9865 // global object should be blocked by access checks on the global
9866 // proxy object. Accessing the object that requires access checks
9867 // is blocked by the access checks on the object itself.
9868 value = CompileRun("Object.getOwnPropertyNames(other).length == 0");
9869 CHECK(value.IsEmpty());
9871 value = CompileRun("Object.getOwnPropertyNames(object).length == 0");
9872 CHECK(value.IsEmpty());
9879 TEST(SuperAccessControl) {
9880 i::FLAG_harmony_classes = true;
9881 v8::Isolate* isolate = CcTest::isolate();
9882 v8::HandleScope handle_scope(isolate);
9883 v8::Handle<v8::ObjectTemplate> obj_template =
9884 v8::ObjectTemplate::New(isolate);
9885 obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
9886 BlockEverythingIndexed);
9888 env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
9891 v8::TryCatch try_catch;
9893 "function f() { return super.hasOwnProperty; };"
9894 "var m = f.toMethod(prohibited);"
9896 CHECK(try_catch.HasCaught());
9900 v8::TryCatch try_catch;
9902 "function f() { return super[42]; };"
9903 "var m = f.toMethod(prohibited);"
9905 CHECK(try_catch.HasCaught());
9909 v8::TryCatch try_catch;
9911 "function f() { super.hasOwnProperty = function () {}; };"
9912 "var m = f.toMethod(prohibited);"
9914 CHECK(try_catch.HasCaught());
9918 v8::TryCatch try_catch;
9920 "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
9923 " super.x = function () {}; "
9925 "var m = f.toMethod(prohibited);"
9927 CHECK(try_catch.HasCaught());
9932 static void IndexedPropertyEnumerator(
9933 const v8::PropertyCallbackInfo<v8::Array>& info) {
9934 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9935 result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
9936 result->Set(1, v8::Object::New(info.GetIsolate()));
9937 info.GetReturnValue().Set(result);
9941 static void NamedPropertyEnumerator(
9942 const v8::PropertyCallbackInfo<v8::Array>& info) {
9943 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
9944 result->Set(0, v8_str("x"));
9945 result->Set(1, v8::Object::New(info.GetIsolate()));
9946 info.GetReturnValue().Set(result);
9950 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) {
9951 v8::Isolate* isolate = CcTest::isolate();
9952 v8::HandleScope handle_scope(isolate);
9953 v8::Handle<v8::ObjectTemplate> obj_template =
9954 v8::ObjectTemplate::New(isolate);
9956 obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
9957 obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
9958 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
9959 IndexedPropertyEnumerator);
9960 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
9961 NamedPropertyEnumerator);
9963 LocalContext context;
9964 v8::Handle<v8::Object> global = context->Global();
9965 global->Set(v8_str("object"), obj_template->NewInstance());
9967 v8::Handle<v8::Value> result =
9968 CompileRun("Object.getOwnPropertyNames(object)");
9969 CHECK(result->IsArray());
9970 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
9971 CHECK_EQ(3, result_array->Length());
9972 CHECK(result_array->Get(0)->IsString());
9973 CHECK(result_array->Get(1)->IsString());
9974 CHECK(result_array->Get(2)->IsString());
9975 CHECK_EQ(v8_str("7"), result_array->Get(0));
9976 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
9977 CHECK_EQ(v8_str("x"), result_array->Get(2));
9981 static void ConstTenGetter(Local<String> name,
9982 const v8::PropertyCallbackInfo<v8::Value>& info) {
9983 info.GetReturnValue().Set(v8_num(10));
9987 THREADED_TEST(CrossDomainAccessors) {
9988 v8::Isolate* isolate = CcTest::isolate();
9989 v8::HandleScope handle_scope(isolate);
9991 v8::Handle<v8::FunctionTemplate> func_template =
9992 v8::FunctionTemplate::New(isolate);
9994 v8::Handle<v8::ObjectTemplate> global_template =
9995 func_template->InstanceTemplate();
9997 v8::Handle<v8::ObjectTemplate> proto_template =
9998 func_template->PrototypeTemplate();
10000 // Add an accessor to proto that's accessible by cross-domain JS code.
10001 proto_template->SetAccessor(v8_str("accessible"),
10003 v8::Handle<Value>(),
10006 // Add an accessor that is not accessible by cross-domain JS code.
10007 global_template->SetAccessor(v8_str("unreachable"),
10008 UnreachableGetter, 0,
10009 v8::Handle<Value>(),
10012 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template);
10015 Local<v8::Object> global = context0->Global();
10016 // Add a normal property that shadows 'accessible'
10017 global->Set(v8_str("accessible"), v8_num(11));
10019 // Enter a new context.
10020 v8::HandleScope scope1(CcTest::isolate());
10021 v8::Local<Context> context1 = Context::New(isolate);
10024 v8::Handle<v8::Object> global1 = context1->Global();
10025 global1->Set(v8_str("other"), global);
10027 // Should return 10, instead of 11
10028 v8::Handle<Value> value = v8_compile("other.accessible")->Run();
10029 CHECK(value->IsNumber());
10030 CHECK_EQ(10, value->Int32Value());
10032 value = v8_compile("other.unreachable")->Run();
10033 CHECK(value.IsEmpty());
10040 static int named_access_count = 0;
10041 static int indexed_access_count = 0;
10043 static bool NamedAccessCounter(Local<v8::Object> global,
10045 v8::AccessType type,
10046 Local<Value> data) {
10047 named_access_count++;
10052 static bool IndexedAccessCounter(Local<v8::Object> global,
10054 v8::AccessType type,
10055 Local<Value> data) {
10056 indexed_access_count++;
10061 // This one is too easily disturbed by other tests.
10062 TEST(AccessControlIC) {
10063 named_access_count = 0;
10064 indexed_access_count = 0;
10066 v8::Isolate* isolate = CcTest::isolate();
10067 v8::HandleScope handle_scope(isolate);
10069 // Create an environment.
10070 v8::Local<Context> context0 = Context::New(isolate);
10073 // Create an object that requires access-check functions to be
10074 // called for cross-domain access.
10075 v8::Handle<v8::ObjectTemplate> object_template =
10076 v8::ObjectTemplate::New(isolate);
10077 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10078 IndexedAccessCounter);
10079 Local<v8::Object> object = object_template->NewInstance();
10081 v8::HandleScope scope1(isolate);
10083 // Create another environment.
10084 v8::Local<Context> context1 = Context::New(isolate);
10087 // Make easy access to the object from the other environment.
10088 v8::Handle<v8::Object> global1 = context1->Global();
10089 global1->Set(v8_str("obj"), object);
10091 v8::Handle<Value> value;
10093 // Check that the named access-control function is called every time.
10094 CompileRun("function testProp(obj) {"
10095 " for (var i = 0; i < 10; i++) obj.prop = 1;"
10096 " for (var j = 0; j < 10; j++) obj.prop;"
10099 value = CompileRun("testProp(obj)");
10100 CHECK(value->IsNumber());
10101 CHECK_EQ(1, value->Int32Value());
10102 CHECK_EQ(21, named_access_count);
10104 // Check that the named access-control function is called every time.
10105 CompileRun("var p = 'prop';"
10106 "function testKeyed(obj) {"
10107 " for (var i = 0; i < 10; i++) obj[p] = 1;"
10108 " for (var j = 0; j < 10; j++) obj[p];"
10111 // Use obj which requires access checks. No inline caching is used
10113 value = CompileRun("testKeyed(obj)");
10114 CHECK(value->IsNumber());
10115 CHECK_EQ(1, value->Int32Value());
10116 CHECK_EQ(42, named_access_count);
10117 // Force the inline caches into generic state and try again.
10118 CompileRun("testKeyed({ a: 0 })");
10119 CompileRun("testKeyed({ b: 0 })");
10120 value = CompileRun("testKeyed(obj)");
10121 CHECK(value->IsNumber());
10122 CHECK_EQ(1, value->Int32Value());
10123 CHECK_EQ(63, named_access_count);
10125 // Check that the indexed access-control function is called every time.
10126 CompileRun("function testIndexed(obj) {"
10127 " for (var i = 0; i < 10; i++) obj[0] = 1;"
10128 " for (var j = 0; j < 10; j++) obj[0];"
10131 value = CompileRun("testIndexed(obj)");
10132 CHECK(value->IsNumber());
10133 CHECK_EQ(1, value->Int32Value());
10134 CHECK_EQ(21, indexed_access_count);
10135 // Force the inline caches into generic state.
10136 CompileRun("testIndexed(new Array(1))");
10137 // Test that the indexed access check is called.
10138 value = CompileRun("testIndexed(obj)");
10139 CHECK(value->IsNumber());
10140 CHECK_EQ(1, value->Int32Value());
10141 CHECK_EQ(42, indexed_access_count);
10143 // Check that the named access check is called when invoking
10144 // functions on an object that requires access checks.
10145 CompileRun("obj.f = function() {}");
10146 CompileRun("function testCallNormal(obj) {"
10147 " for (var i = 0; i < 10; i++) obj.f();"
10149 CompileRun("testCallNormal(obj)");
10150 CHECK_EQ(74, named_access_count);
10152 // Force obj into slow case.
10153 value = CompileRun("delete obj.prop");
10154 CHECK(value->BooleanValue());
10155 // Force inline caches into dictionary probing mode.
10156 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);");
10157 // Test that the named access check is called.
10158 value = CompileRun("testProp(obj);");
10159 CHECK(value->IsNumber());
10160 CHECK_EQ(1, value->Int32Value());
10161 CHECK_EQ(96, named_access_count);
10163 // Force the call inline cache into dictionary probing mode.
10164 CompileRun("o.f = function() {}; testCallNormal(o)");
10165 // Test that the named access check is still called for each
10166 // invocation of the function.
10167 value = CompileRun("testCallNormal(obj)");
10168 CHECK_EQ(106, named_access_count);
10175 static bool NamedAccessFlatten(Local<v8::Object> global,
10177 v8::AccessType type,
10178 Local<Value> data) {
10182 CHECK(name->IsString());
10184 memset(buf, 0x1, sizeof(buf));
10185 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf));
10188 uint16_t buf2[100];
10190 memset(buf, 0x1, sizeof(buf));
10191 len = name.As<String>()->Write(buf2);
10198 static bool IndexedAccessFlatten(Local<v8::Object> global,
10200 v8::AccessType type,
10201 Local<Value> data) {
10206 // Regression test. In access checks, operations that may cause
10207 // garbage collection are not allowed. It used to be the case that
10208 // using the Write operation on a string could cause a garbage
10209 // collection due to flattening of the string. This is no longer the
10211 THREADED_TEST(AccessControlFlatten) {
10212 named_access_count = 0;
10213 indexed_access_count = 0;
10215 v8::Isolate* isolate = CcTest::isolate();
10216 v8::HandleScope handle_scope(isolate);
10218 // Create an environment.
10219 v8::Local<Context> context0 = Context::New(isolate);
10222 // Create an object that requires access-check functions to be
10223 // called for cross-domain access.
10224 v8::Handle<v8::ObjectTemplate> object_template =
10225 v8::ObjectTemplate::New(isolate);
10226 object_template->SetAccessCheckCallbacks(NamedAccessFlatten,
10227 IndexedAccessFlatten);
10228 Local<v8::Object> object = object_template->NewInstance();
10230 v8::HandleScope scope1(isolate);
10232 // Create another environment.
10233 v8::Local<Context> context1 = Context::New(isolate);
10236 // Make easy access to the object from the other environment.
10237 v8::Handle<v8::Object> global1 = context1->Global();
10238 global1->Set(v8_str("obj"), object);
10240 v8::Handle<Value> value;
10242 value = v8_compile("var p = 'as' + 'df';")->Run();
10243 value = v8_compile("obj[p];")->Run();
10250 static void AccessControlNamedGetter(
10252 const v8::PropertyCallbackInfo<v8::Value>& info) {
10253 info.GetReturnValue().Set(42);
10257 static void AccessControlNamedSetter(
10259 Local<Value> value,
10260 const v8::PropertyCallbackInfo<v8::Value>& info) {
10261 info.GetReturnValue().Set(value);
10265 static void AccessControlIndexedGetter(
10267 const v8::PropertyCallbackInfo<v8::Value>& info) {
10268 info.GetReturnValue().Set(v8_num(42));
10272 static void AccessControlIndexedSetter(
10274 Local<Value> value,
10275 const v8::PropertyCallbackInfo<v8::Value>& info) {
10276 info.GetReturnValue().Set(value);
10280 THREADED_TEST(AccessControlInterceptorIC) {
10281 named_access_count = 0;
10282 indexed_access_count = 0;
10284 v8::Isolate* isolate = CcTest::isolate();
10285 v8::HandleScope handle_scope(isolate);
10287 // Create an environment.
10288 v8::Local<Context> context0 = Context::New(isolate);
10291 // Create an object that requires access-check functions to be
10292 // called for cross-domain access. The object also has interceptors
10294 v8::Handle<v8::ObjectTemplate> object_template =
10295 v8::ObjectTemplate::New(isolate);
10296 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
10297 IndexedAccessCounter);
10298 object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
10299 AccessControlNamedSetter);
10300 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
10301 AccessControlIndexedSetter);
10302 Local<v8::Object> object = object_template->NewInstance();
10304 v8::HandleScope scope1(isolate);
10306 // Create another environment.
10307 v8::Local<Context> context1 = Context::New(isolate);
10310 // Make easy access to the object from the other environment.
10311 v8::Handle<v8::Object> global1 = context1->Global();
10312 global1->Set(v8_str("obj"), object);
10314 v8::Handle<Value> value;
10316 // Check that the named access-control function is called every time
10317 // eventhough there is an interceptor on the object.
10318 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run();
10319 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;"
10321 CHECK(value->IsNumber());
10322 CHECK_EQ(42, value->Int32Value());
10323 CHECK_EQ(21, named_access_count);
10325 value = v8_compile("var p = 'x';")->Run();
10326 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run();
10327 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];"
10329 CHECK(value->IsNumber());
10330 CHECK_EQ(42, value->Int32Value());
10331 CHECK_EQ(42, named_access_count);
10333 // Check that the indexed access-control function is called every
10334 // time eventhough there is an interceptor on the object.
10335 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run();
10336 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];"
10338 CHECK(value->IsNumber());
10339 CHECK_EQ(42, value->Int32Value());
10340 CHECK_EQ(21, indexed_access_count);
10347 THREADED_TEST(Version) {
10348 v8::V8::GetVersion();
10352 static void InstanceFunctionCallback(
10353 const v8::FunctionCallbackInfo<v8::Value>& args) {
10354 ApiTestFuzzer::Fuzz();
10355 args.GetReturnValue().Set(v8_num(12));
10359 THREADED_TEST(InstanceProperties) {
10360 LocalContext context;
10361 v8::Isolate* isolate = context->GetIsolate();
10362 v8::HandleScope handle_scope(isolate);
10364 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10365 Local<ObjectTemplate> instance = t->InstanceTemplate();
10367 instance->Set(v8_str("x"), v8_num(42));
10368 instance->Set(v8_str("f"),
10369 v8::FunctionTemplate::New(isolate, InstanceFunctionCallback));
10371 Local<Value> o = t->GetFunction()->NewInstance();
10373 context->Global()->Set(v8_str("i"), o);
10374 Local<Value> value = CompileRun("i.x");
10375 CHECK_EQ(42, value->Int32Value());
10377 value = CompileRun("i.f()");
10378 CHECK_EQ(12, value->Int32Value());
10382 static void GlobalObjectInstancePropertiesGet(
10384 const v8::PropertyCallbackInfo<v8::Value>&) {
10385 ApiTestFuzzer::Fuzz();
10389 THREADED_TEST(GlobalObjectInstanceProperties) {
10390 v8::Isolate* isolate = CcTest::isolate();
10391 v8::HandleScope handle_scope(isolate);
10393 Local<Value> global_object;
10395 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10396 t->InstanceTemplate()->SetNamedPropertyHandler(
10397 GlobalObjectInstancePropertiesGet);
10398 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10399 instance_template->Set(v8_str("x"), v8_num(42));
10400 instance_template->Set(v8_str("f"),
10401 v8::FunctionTemplate::New(isolate,
10402 InstanceFunctionCallback));
10404 // The script to check how Crankshaft compiles missing global function
10405 // invocations. function g is not defined and should throw on call.
10406 const char* script =
10407 "function wrapper(call) {"
10408 " var x = 0, y = 1;"
10409 " for (var i = 0; i < 1000; i++) {"
10415 "for (var i = 0; i < 17; i++) wrapper(false);"
10417 "try { wrapper(true); } catch (e) { thrown = 1; };"
10421 LocalContext env(NULL, instance_template);
10422 // Hold on to the global object so it can be used again in another
10423 // environment initialization.
10424 global_object = env->Global();
10426 Local<Value> value = CompileRun("x");
10427 CHECK_EQ(42, value->Int32Value());
10428 value = CompileRun("f()");
10429 CHECK_EQ(12, value->Int32Value());
10430 value = CompileRun(script);
10431 CHECK_EQ(1, value->Int32Value());
10435 // Create new environment reusing the global object.
10436 LocalContext env(NULL, instance_template, global_object);
10437 Local<Value> value = CompileRun("x");
10438 CHECK_EQ(42, value->Int32Value());
10439 value = CompileRun("f()");
10440 CHECK_EQ(12, value->Int32Value());
10441 value = CompileRun(script);
10442 CHECK_EQ(1, value->Int32Value());
10447 THREADED_TEST(CallKnownGlobalReceiver) {
10448 v8::Isolate* isolate = CcTest::isolate();
10449 v8::HandleScope handle_scope(isolate);
10451 Local<Value> global_object;
10453 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10454 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
10456 // The script to check that we leave global object not
10457 // global object proxy on stack when we deoptimize from inside
10458 // arguments evaluation.
10459 // To provoke error we need to both force deoptimization
10460 // from arguments evaluation and to force CallIC to take
10461 // CallIC_Miss code path that can't cope with global proxy.
10462 const char* script =
10463 "function bar(x, y) { try { } finally { } }"
10464 "function baz(x) { try { } finally { } }"
10465 "function bom(x) { try { } finally { } }"
10466 "function foo(x) { bar([x], bom(2)); }"
10467 "for (var i = 0; i < 10000; i++) foo(1);"
10472 LocalContext env(NULL, instance_template);
10473 // Hold on to the global object so it can be used again in another
10474 // environment initialization.
10475 global_object = env->Global();
10476 foo = CompileRun(script);
10480 // Create new environment reusing the global object.
10481 LocalContext env(NULL, instance_template, global_object);
10482 env->Global()->Set(v8_str("foo"), foo);
10483 CompileRun("foo()");
10488 static void ShadowFunctionCallback(
10489 const v8::FunctionCallbackInfo<v8::Value>& args) {
10490 ApiTestFuzzer::Fuzz();
10491 args.GetReturnValue().Set(v8_num(42));
10495 static int shadow_y;
10496 static int shadow_y_setter_call_count;
10497 static int shadow_y_getter_call_count;
10500 static void ShadowYSetter(Local<String>,
10502 const v8::PropertyCallbackInfo<void>&) {
10503 shadow_y_setter_call_count++;
10508 static void ShadowYGetter(Local<String> name,
10509 const v8::PropertyCallbackInfo<v8::Value>& info) {
10510 ApiTestFuzzer::Fuzz();
10511 shadow_y_getter_call_count++;
10512 info.GetReturnValue().Set(v8_num(shadow_y));
10516 static void ShadowIndexedGet(uint32_t index,
10517 const v8::PropertyCallbackInfo<v8::Value>&) {
10521 static void ShadowNamedGet(Local<String> key,
10522 const v8::PropertyCallbackInfo<v8::Value>&) {
10526 THREADED_TEST(ShadowObject) {
10527 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0;
10528 v8::Isolate* isolate = CcTest::isolate();
10529 v8::HandleScope handle_scope(isolate);
10531 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(isolate);
10532 LocalContext context(NULL, global_template);
10534 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10535 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
10536 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
10537 Local<ObjectTemplate> proto = t->PrototypeTemplate();
10538 Local<ObjectTemplate> instance = t->InstanceTemplate();
10540 proto->Set(v8_str("f"),
10541 v8::FunctionTemplate::New(isolate,
10542 ShadowFunctionCallback,
10544 proto->Set(v8_str("x"), v8_num(12));
10546 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
10548 Local<Value> o = t->GetFunction()->NewInstance();
10549 context->Global()->Set(v8_str("__proto__"), o);
10551 Local<Value> value =
10552 CompileRun("this.propertyIsEnumerable(0)");
10553 CHECK(value->IsBoolean());
10554 CHECK(!value->BooleanValue());
10556 value = CompileRun("x");
10557 CHECK_EQ(12, value->Int32Value());
10559 value = CompileRun("f()");
10560 CHECK_EQ(42, value->Int32Value());
10562 CompileRun("y = 43");
10563 CHECK_EQ(1, shadow_y_setter_call_count);
10564 value = CompileRun("y");
10565 CHECK_EQ(1, shadow_y_getter_call_count);
10566 CHECK_EQ(42, value->Int32Value());
10570 THREADED_TEST(HiddenPrototype) {
10571 LocalContext context;
10572 v8::Isolate* isolate = context->GetIsolate();
10573 v8::HandleScope handle_scope(isolate);
10575 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10576 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10577 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10578 t1->SetHiddenPrototype(true);
10579 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10580 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10581 t2->SetHiddenPrototype(true);
10582 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10583 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10584 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10586 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10587 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10588 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10589 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10591 // Setting the prototype on an object skips hidden prototypes.
10592 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10593 o0->Set(v8_str("__proto__"), o1);
10594 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10595 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10596 o0->Set(v8_str("__proto__"), o2);
10597 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10598 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10599 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10600 o0->Set(v8_str("__proto__"), o3);
10601 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10602 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10603 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10604 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10606 // Getting the prototype of o0 should get the first visible one
10607 // which is o3. Therefore, z should not be defined on the prototype
10609 Local<Value> proto = o0->Get(v8_str("__proto__"));
10610 CHECK(proto->IsObject());
10611 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined());
10615 THREADED_TEST(HiddenPrototypeSet) {
10616 LocalContext context;
10617 v8::Isolate* isolate = context->GetIsolate();
10618 v8::HandleScope handle_scope(isolate);
10620 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(isolate);
10621 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(isolate);
10622 ht->SetHiddenPrototype(true);
10623 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(isolate);
10624 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10626 Local<v8::Object> o = ot->GetFunction()->NewInstance();
10627 Local<v8::Object> h = ht->GetFunction()->NewInstance();
10628 Local<v8::Object> p = pt->GetFunction()->NewInstance();
10629 o->Set(v8_str("__proto__"), h);
10630 h->Set(v8_str("__proto__"), p);
10632 // Setting a property that exists on the hidden prototype goes there.
10633 o->Set(v8_str("x"), v8_num(7));
10634 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value());
10635 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value());
10636 CHECK(p->Get(v8_str("x"))->IsUndefined());
10638 // Setting a new property should not be forwarded to the hidden prototype.
10639 o->Set(v8_str("y"), v8_num(6));
10640 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value());
10641 CHECK(h->Get(v8_str("y"))->IsUndefined());
10642 CHECK(p->Get(v8_str("y"))->IsUndefined());
10644 // Setting a property that only exists on a prototype of the hidden prototype
10645 // is treated normally again.
10646 p->Set(v8_str("z"), v8_num(8));
10647 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value());
10648 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10649 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10650 o->Set(v8_str("z"), v8_num(9));
10651 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value());
10652 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value());
10653 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value());
10657 // Regression test for issue 2457.
10658 THREADED_TEST(HiddenPrototypeIdentityHash) {
10659 LocalContext context;
10660 v8::HandleScope handle_scope(context->GetIsolate());
10662 Handle<FunctionTemplate> t = FunctionTemplate::New(context->GetIsolate());
10663 t->SetHiddenPrototype(true);
10664 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75));
10665 Handle<Object> p = t->GetFunction()->NewInstance();
10666 Handle<Object> o = Object::New(context->GetIsolate());
10667 o->SetPrototype(p);
10669 int hash = o->GetIdentityHash();
10671 o->Set(v8_str("foo"), v8_num(42));
10672 DCHECK_EQ(hash, o->GetIdentityHash());
10676 THREADED_TEST(SetPrototype) {
10677 LocalContext context;
10678 v8::Isolate* isolate = context->GetIsolate();
10679 v8::HandleScope handle_scope(isolate);
10681 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
10682 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0));
10683 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10684 t1->SetHiddenPrototype(true);
10685 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1));
10686 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10687 t2->SetHiddenPrototype(true);
10688 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2));
10689 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10690 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3));
10692 Local<v8::Object> o0 = t0->GetFunction()->NewInstance();
10693 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10694 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10695 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10697 // Setting the prototype on an object does not skip hidden prototypes.
10698 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10699 CHECK(o0->SetPrototype(o1));
10700 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10701 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10702 CHECK(o1->SetPrototype(o2));
10703 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10704 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10705 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10706 CHECK(o2->SetPrototype(o3));
10707 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value());
10708 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value());
10709 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value());
10710 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value());
10712 // Getting the prototype of o0 should get the first visible one
10713 // which is o3. Therefore, z should not be defined on the prototype
10715 Local<Value> proto = o0->Get(v8_str("__proto__"));
10716 CHECK(proto->IsObject());
10717 CHECK_EQ(proto.As<v8::Object>(), o3);
10719 // However, Object::GetPrototype ignores hidden prototype.
10720 Local<Value> proto0 = o0->GetPrototype();
10721 CHECK(proto0->IsObject());
10722 CHECK_EQ(proto0.As<v8::Object>(), o1);
10724 Local<Value> proto1 = o1->GetPrototype();
10725 CHECK(proto1->IsObject());
10726 CHECK_EQ(proto1.As<v8::Object>(), o2);
10728 Local<Value> proto2 = o2->GetPrototype();
10729 CHECK(proto2->IsObject());
10730 CHECK_EQ(proto2.As<v8::Object>(), o3);
10734 // Getting property names of an object with a prototype chain that
10735 // triggers dictionary elements in GetOwnPropertyNames() shouldn't
10736 // crash the runtime.
10737 THREADED_TEST(Regress91517) {
10738 i::FLAG_allow_natives_syntax = true;
10739 LocalContext context;
10740 v8::Isolate* isolate = context->GetIsolate();
10741 v8::HandleScope handle_scope(isolate);
10743 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10744 t1->SetHiddenPrototype(true);
10745 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1));
10746 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10747 t2->SetHiddenPrototype(true);
10748 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2));
10749 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New(isolate));
10750 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2));
10751 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
10752 t3->SetHiddenPrototype(true);
10753 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3));
10754 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(isolate);
10755 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4));
10757 // Force dictionary-based properties.
10758 i::ScopedVector<char> name_buf(1024);
10759 for (int i = 1; i <= 1000; i++) {
10760 i::SNPrintF(name_buf, "sdf%d", i);
10761 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2));
10764 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10765 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10766 Local<v8::Object> o3 = t3->GetFunction()->NewInstance();
10767 Local<v8::Object> o4 = t4->GetFunction()->NewInstance();
10769 // Create prototype chain of hidden prototypes.
10770 CHECK(o4->SetPrototype(o3));
10771 CHECK(o3->SetPrototype(o2));
10772 CHECK(o2->SetPrototype(o1));
10774 // Call the runtime version of GetOwnPropertyNames() on the natively
10775 // created object through JavaScript.
10776 context->Global()->Set(v8_str("obj"), o4);
10777 // PROPERTY_ATTRIBUTES_NONE = 0
10778 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10780 ExpectInt32("names.length", 1006);
10781 ExpectTrue("names.indexOf(\"baz\") >= 0");
10782 ExpectTrue("names.indexOf(\"boo\") >= 0");
10783 ExpectTrue("names.indexOf(\"foo\") >= 0");
10784 ExpectTrue("names.indexOf(\"fuz1\") >= 0");
10785 ExpectTrue("names.indexOf(\"fuz2\") >= 0");
10786 ExpectFalse("names[1005] == undefined");
10790 // Getting property names of an object with a hidden and inherited
10791 // prototype should not duplicate the accessor properties inherited.
10792 THREADED_TEST(Regress269562) {
10793 i::FLAG_allow_natives_syntax = true;
10794 LocalContext context;
10795 v8::HandleScope handle_scope(context->GetIsolate());
10797 Local<v8::FunctionTemplate> t1 =
10798 v8::FunctionTemplate::New(context->GetIsolate());
10799 t1->SetHiddenPrototype(true);
10801 Local<v8::ObjectTemplate> i1 = t1->InstanceTemplate();
10802 i1->SetAccessor(v8_str("foo"),
10803 SimpleAccessorGetter, SimpleAccessorSetter);
10804 i1->SetAccessor(v8_str("bar"),
10805 SimpleAccessorGetter, SimpleAccessorSetter);
10806 i1->SetAccessor(v8_str("baz"),
10807 SimpleAccessorGetter, SimpleAccessorSetter);
10808 i1->Set(v8_str("n1"), v8_num(1));
10809 i1->Set(v8_str("n2"), v8_num(2));
10811 Local<v8::Object> o1 = t1->GetFunction()->NewInstance();
10812 Local<v8::FunctionTemplate> t2 =
10813 v8::FunctionTemplate::New(context->GetIsolate());
10814 t2->SetHiddenPrototype(true);
10816 // Inherit from t1 and mark prototype as hidden.
10818 t2->InstanceTemplate()->Set(v8_str("mine"), v8_num(4));
10820 Local<v8::Object> o2 = t2->GetFunction()->NewInstance();
10821 CHECK(o2->SetPrototype(o1));
10823 v8::Local<v8::Symbol> sym =
10824 v8::Symbol::New(context->GetIsolate(), v8_str("s1"));
10825 o1->Set(sym, v8_num(3));
10826 o1->SetHiddenValue(
10827 v8_str("h1"), v8::Integer::New(context->GetIsolate(), 2013));
10829 // Call the runtime version of GetOwnPropertyNames() on
10830 // the natively created object through JavaScript.
10831 context->Global()->Set(v8_str("obj"), o2);
10832 context->Global()->Set(v8_str("sym"), sym);
10833 // PROPERTY_ATTRIBUTES_NONE = 0
10834 CompileRun("var names = %GetOwnPropertyNames(obj, 0);");
10836 ExpectInt32("names.length", 7);
10837 ExpectTrue("names.indexOf(\"foo\") >= 0");
10838 ExpectTrue("names.indexOf(\"bar\") >= 0");
10839 ExpectTrue("names.indexOf(\"baz\") >= 0");
10840 ExpectTrue("names.indexOf(\"n1\") >= 0");
10841 ExpectTrue("names.indexOf(\"n2\") >= 0");
10842 ExpectTrue("names.indexOf(sym) >= 0");
10843 ExpectTrue("names.indexOf(\"mine\") >= 0");
10847 THREADED_TEST(FunctionReadOnlyPrototype) {
10848 LocalContext context;
10849 v8::Isolate* isolate = context->GetIsolate();
10850 v8::HandleScope handle_scope(isolate);
10852 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10853 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10854 t1->ReadOnlyPrototype();
10855 context->Global()->Set(v8_str("func1"), t1->GetFunction());
10856 // Configured value of ReadOnly flag.
10859 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');"
10860 " return (descriptor['writable'] == false);"
10861 "})()")->BooleanValue());
10862 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value());
10864 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value());
10866 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
10867 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(isolate, 42));
10868 context->Global()->Set(v8_str("func2"), t2->GetFunction());
10869 // Default value of ReadOnly flag.
10872 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');"
10873 " return (descriptor['writable'] == true);"
10874 "})()")->BooleanValue());
10875 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value());
10879 THREADED_TEST(SetPrototypeThrows) {
10880 LocalContext context;
10881 v8::Isolate* isolate = context->GetIsolate();
10882 v8::HandleScope handle_scope(isolate);
10884 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
10886 Local<v8::Object> o0 = t->GetFunction()->NewInstance();
10887 Local<v8::Object> o1 = t->GetFunction()->NewInstance();
10889 CHECK(o0->SetPrototype(o1));
10890 // If setting the prototype leads to the cycle, SetPrototype should
10891 // return false and keep VM in sane state.
10892 v8::TryCatch try_catch;
10893 CHECK(!o1->SetPrototype(o0));
10894 CHECK(!try_catch.HasCaught());
10895 DCHECK(!CcTest::i_isolate()->has_pending_exception());
10897 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value());
10901 THREADED_TEST(FunctionRemovePrototype) {
10902 LocalContext context;
10903 v8::Isolate* isolate = context->GetIsolate();
10904 v8::HandleScope handle_scope(isolate);
10906 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
10907 t1->RemovePrototype();
10908 Local<v8::Function> fun = t1->GetFunction();
10909 context->Global()->Set(v8_str("fun"), fun);
10910 CHECK(!CompileRun("'prototype' in fun")->BooleanValue());
10912 v8::TryCatch try_catch;
10913 CompileRun("new fun()");
10914 CHECK(try_catch.HasCaught());
10917 fun->NewInstance();
10918 CHECK(try_catch.HasCaught());
10922 THREADED_TEST(GetterSetterExceptions) {
10923 LocalContext context;
10924 v8::Isolate* isolate = context->GetIsolate();
10925 v8::HandleScope handle_scope(isolate);
10927 "function Foo() { };"
10928 "function Throw() { throw 5; };"
10930 "x.__defineSetter__('set', Throw);"
10931 "x.__defineGetter__('get', Throw);");
10932 Local<v8::Object> x =
10933 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x")));
10934 v8::TryCatch try_catch;
10935 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10936 x->Get(v8_str("get"));
10937 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10938 x->Get(v8_str("get"));
10939 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10940 x->Get(v8_str("get"));
10941 x->Set(v8_str("set"), v8::Integer::New(isolate, 8));
10942 x->Get(v8_str("get"));
10946 THREADED_TEST(Constructor) {
10947 LocalContext context;
10948 v8::Isolate* isolate = context->GetIsolate();
10949 v8::HandleScope handle_scope(isolate);
10950 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
10951 templ->SetClassName(v8_str("Fun"));
10952 Local<Function> cons = templ->GetFunction();
10953 context->Global()->Set(v8_str("Fun"), cons);
10954 Local<v8::Object> inst = cons->NewInstance();
10955 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst));
10956 CHECK(obj->IsJSObject());
10957 Local<Value> value = CompileRun("(new Fun()).constructor === Fun");
10958 CHECK(value->BooleanValue());
10962 static void ConstructorCallback(
10963 const v8::FunctionCallbackInfo<v8::Value>& args) {
10964 ApiTestFuzzer::Fuzz();
10965 Local<Object> This;
10967 if (args.IsConstructCall()) {
10968 Local<Object> Holder = args.Holder();
10969 This = Object::New(args.GetIsolate());
10970 Local<Value> proto = Holder->GetPrototype();
10971 if (proto->IsObject()) {
10972 This->SetPrototype(proto);
10975 This = args.This();
10978 This->Set(v8_str("a"), args[0]);
10979 args.GetReturnValue().Set(This);
10983 static void FakeConstructorCallback(
10984 const v8::FunctionCallbackInfo<v8::Value>& args) {
10985 ApiTestFuzzer::Fuzz();
10986 args.GetReturnValue().Set(args[0]);
10990 THREADED_TEST(ConstructorForObject) {
10991 LocalContext context;
10992 v8::Isolate* isolate = context->GetIsolate();
10993 v8::HandleScope handle_scope(isolate);
10995 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
10996 instance_template->SetCallAsFunctionHandler(ConstructorCallback);
10997 Local<Object> instance = instance_template->NewInstance();
10998 context->Global()->Set(v8_str("obj"), instance);
10999 v8::TryCatch try_catch;
11000 Local<Value> value;
11001 CHECK(!try_catch.HasCaught());
11003 // Call the Object's constructor with a 32-bit signed integer.
11004 value = CompileRun("(function() { var o = new obj(28); return o.a; })()");
11005 CHECK(!try_catch.HasCaught());
11006 CHECK(value->IsInt32());
11007 CHECK_EQ(28, value->Int32Value());
11009 Local<Value> args1[] = { v8_num(28) };
11010 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1);
11011 CHECK(value_obj1->IsObject());
11012 Local<Object> object1 = Local<Object>::Cast(value_obj1);
11013 value = object1->Get(v8_str("a"));
11014 CHECK(value->IsInt32());
11015 CHECK(!try_catch.HasCaught());
11016 CHECK_EQ(28, value->Int32Value());
11018 // Call the Object's constructor with a String.
11019 value = CompileRun(
11020 "(function() { var o = new obj('tipli'); return o.a; })()");
11021 CHECK(!try_catch.HasCaught());
11022 CHECK(value->IsString());
11023 String::Utf8Value string_value1(value->ToString());
11024 CHECK_EQ("tipli", *string_value1);
11026 Local<Value> args2[] = { v8_str("tipli") };
11027 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2);
11028 CHECK(value_obj2->IsObject());
11029 Local<Object> object2 = Local<Object>::Cast(value_obj2);
11030 value = object2->Get(v8_str("a"));
11031 CHECK(!try_catch.HasCaught());
11032 CHECK(value->IsString());
11033 String::Utf8Value string_value2(value->ToString());
11034 CHECK_EQ("tipli", *string_value2);
11036 // Call the Object's constructor with a Boolean.
11037 value = CompileRun("(function() { var o = new obj(true); return o.a; })()");
11038 CHECK(!try_catch.HasCaught());
11039 CHECK(value->IsBoolean());
11040 CHECK_EQ(true, value->BooleanValue());
11042 Handle<Value> args3[] = { v8::True(isolate) };
11043 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3);
11044 CHECK(value_obj3->IsObject());
11045 Local<Object> object3 = Local<Object>::Cast(value_obj3);
11046 value = object3->Get(v8_str("a"));
11047 CHECK(!try_catch.HasCaught());
11048 CHECK(value->IsBoolean());
11049 CHECK_EQ(true, value->BooleanValue());
11051 // Call the Object's constructor with undefined.
11052 Handle<Value> args4[] = { v8::Undefined(isolate) };
11053 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4);
11054 CHECK(value_obj4->IsObject());
11055 Local<Object> object4 = Local<Object>::Cast(value_obj4);
11056 value = object4->Get(v8_str("a"));
11057 CHECK(!try_catch.HasCaught());
11058 CHECK(value->IsUndefined());
11060 // Call the Object's constructor with null.
11061 Handle<Value> args5[] = { v8::Null(isolate) };
11062 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5);
11063 CHECK(value_obj5->IsObject());
11064 Local<Object> object5 = Local<Object>::Cast(value_obj5);
11065 value = object5->Get(v8_str("a"));
11066 CHECK(!try_catch.HasCaught());
11067 CHECK(value->IsNull());
11070 // Check exception handling when there is no constructor set for the Object.
11071 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11072 Local<Object> instance = instance_template->NewInstance();
11073 context->Global()->Set(v8_str("obj2"), instance);
11074 v8::TryCatch try_catch;
11075 Local<Value> value;
11076 CHECK(!try_catch.HasCaught());
11078 value = CompileRun("new obj2(28)");
11079 CHECK(try_catch.HasCaught());
11080 String::Utf8Value exception_value1(try_catch.Exception());
11081 CHECK_EQ("TypeError: object is not a function", *exception_value1);
11084 Local<Value> args[] = { v8_num(29) };
11085 value = instance->CallAsConstructor(1, args);
11086 CHECK(try_catch.HasCaught());
11087 String::Utf8Value exception_value2(try_catch.Exception());
11088 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2);
11092 // Check the case when constructor throws exception.
11093 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11094 instance_template->SetCallAsFunctionHandler(ThrowValue);
11095 Local<Object> instance = instance_template->NewInstance();
11096 context->Global()->Set(v8_str("obj3"), instance);
11097 v8::TryCatch try_catch;
11098 Local<Value> value;
11099 CHECK(!try_catch.HasCaught());
11101 value = CompileRun("new obj3(22)");
11102 CHECK(try_catch.HasCaught());
11103 String::Utf8Value exception_value1(try_catch.Exception());
11104 CHECK_EQ("22", *exception_value1);
11107 Local<Value> args[] = { v8_num(23) };
11108 value = instance->CallAsConstructor(1, args);
11109 CHECK(try_catch.HasCaught());
11110 String::Utf8Value exception_value2(try_catch.Exception());
11111 CHECK_EQ("23", *exception_value2);
11115 // Check whether constructor returns with an object or non-object.
11116 { Local<FunctionTemplate> function_template =
11117 FunctionTemplate::New(isolate, FakeConstructorCallback);
11118 Local<Function> function = function_template->GetFunction();
11119 Local<Object> instance1 = function;
11120 context->Global()->Set(v8_str("obj4"), instance1);
11121 v8::TryCatch try_catch;
11122 Local<Value> value;
11123 CHECK(!try_catch.HasCaught());
11125 CHECK(instance1->IsObject());
11126 CHECK(instance1->IsFunction());
11128 value = CompileRun("new obj4(28)");
11129 CHECK(!try_catch.HasCaught());
11130 CHECK(value->IsObject());
11132 Local<Value> args1[] = { v8_num(28) };
11133 value = instance1->CallAsConstructor(1, args1);
11134 CHECK(!try_catch.HasCaught());
11135 CHECK(value->IsObject());
11137 Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11138 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback);
11139 Local<Object> instance2 = instance_template->NewInstance();
11140 context->Global()->Set(v8_str("obj5"), instance2);
11141 CHECK(!try_catch.HasCaught());
11143 CHECK(instance2->IsObject());
11144 CHECK(!instance2->IsFunction());
11146 value = CompileRun("new obj5(28)");
11147 CHECK(!try_catch.HasCaught());
11148 CHECK(!value->IsObject());
11150 Local<Value> args2[] = { v8_num(28) };
11151 value = instance2->CallAsConstructor(1, args2);
11152 CHECK(!try_catch.HasCaught());
11153 CHECK(!value->IsObject());
11158 THREADED_TEST(FunctionDescriptorException) {
11159 LocalContext context;
11160 v8::Isolate* isolate = context->GetIsolate();
11161 v8::HandleScope handle_scope(isolate);
11162 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
11163 templ->SetClassName(v8_str("Fun"));
11164 Local<Function> cons = templ->GetFunction();
11165 context->Global()->Set(v8_str("Fun"), cons);
11166 Local<Value> value = CompileRun(
11167 "function test() {"
11169 " (new Fun()).blah()"
11171 " var str = String(e);"
11172 // " if (str.indexOf('TypeError') == -1) return 1;"
11173 // " if (str.indexOf('[object Fun]') != -1) return 2;"
11174 // " if (str.indexOf('#<Fun>') == -1) return 3;"
11180 CHECK_EQ(0, value->Int32Value());
11184 THREADED_TEST(EvalAliasedDynamic) {
11185 LocalContext current;
11186 v8::HandleScope scope(current->GetIsolate());
11188 // Tests where aliased eval can only be resolved dynamically.
11189 Local<Script> script = v8_compile(
11192 " with (x) { return eval('foo'); }"
11195 "result1 = f(new Object());"
11196 "result2 = f(this);"
11197 "var x = new Object();"
11198 "x.eval = function(x) { return 1; };"
11199 "result3 = f(x);");
11201 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value());
11202 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value());
11203 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value());
11205 v8::TryCatch try_catch;
11206 script = v8_compile(
11209 " with (x) { return eval('bar'); }"
11211 "result4 = f(this)");
11213 CHECK(!try_catch.HasCaught());
11214 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value());
11220 THREADED_TEST(CrossEval) {
11221 v8::HandleScope scope(CcTest::isolate());
11222 LocalContext other;
11223 LocalContext current;
11225 Local<String> token = v8_str("<security token>");
11226 other->SetSecurityToken(token);
11227 current->SetSecurityToken(token);
11229 // Set up reference from current to other.
11230 current->Global()->Set(v8_str("other"), other->Global());
11232 // Check that new variables are introduced in other context.
11233 Local<Script> script = v8_compile("other.eval('var foo = 1234')");
11235 Local<Value> foo = other->Global()->Get(v8_str("foo"));
11236 CHECK_EQ(1234, foo->Int32Value());
11237 CHECK(!current->Global()->Has(v8_str("foo")));
11239 // Check that writing to non-existing properties introduces them in
11240 // the other context.
11241 script = v8_compile("other.eval('na = 1234')");
11243 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value());
11244 CHECK(!current->Global()->Has(v8_str("na")));
11246 // Check that global variables in current context are not visible in other
11248 v8::TryCatch try_catch;
11249 script = v8_compile("var bar = 42; other.eval('bar');");
11250 Local<Value> result = script->Run();
11251 CHECK(try_catch.HasCaught());
11254 // Check that local variables in current context are not visible in other
11256 script = v8_compile(
11259 " return other.eval('baz');"
11261 result = script->Run();
11262 CHECK(try_catch.HasCaught());
11265 // Check that global variables in the other environment are visible
11266 // when evaluting code.
11267 other->Global()->Set(v8_str("bis"), v8_num(1234));
11268 script = v8_compile("other.eval('bis')");
11269 CHECK_EQ(1234, script->Run()->Int32Value());
11270 CHECK(!try_catch.HasCaught());
11272 // Check that the 'this' pointer points to the global object evaluating
11274 other->Global()->Set(v8_str("t"), other->Global());
11275 script = v8_compile("other.eval('this == t')");
11276 result = script->Run();
11277 CHECK(result->IsTrue());
11278 CHECK(!try_catch.HasCaught());
11280 // Check that variables introduced in with-statement are not visible in
11282 script = v8_compile("with({x:2}){other.eval('x')}");
11283 result = script->Run();
11284 CHECK(try_catch.HasCaught());
11287 // Check that you cannot use 'eval.call' with another object than the
11288 // current global object.
11289 script = v8_compile("other.y = 1; eval.call(other, 'y')");
11290 result = script->Run();
11291 CHECK(try_catch.HasCaught());
11295 // Test that calling eval in a context which has been detached from
11296 // its global throws an exception. This behavior is consistent with
11297 // other JavaScript implementations.
11298 THREADED_TEST(EvalInDetachedGlobal) {
11299 v8::Isolate* isolate = CcTest::isolate();
11300 v8::HandleScope scope(isolate);
11302 v8::Local<Context> context0 = Context::New(isolate);
11303 v8::Local<Context> context1 = Context::New(isolate);
11305 // Set up function in context0 that uses eval from context0.
11307 v8::Handle<v8::Value> fun =
11308 CompileRun("var x = 42;"
11311 " return function(s) { return e(s); }"
11315 // Put the function into context1 and call it before and after
11316 // detaching the global. Before detaching, the call succeeds and
11317 // after detaching and exception is thrown.
11319 context1->Global()->Set(v8_str("fun"), fun);
11320 v8::Handle<v8::Value> x_value = CompileRun("fun('x')");
11321 CHECK_EQ(42, x_value->Int32Value());
11322 context0->DetachGlobal();
11323 v8::TryCatch catcher;
11324 x_value = CompileRun("fun('x')");
11325 CHECK(x_value.IsEmpty());
11326 CHECK(catcher.HasCaught());
11331 THREADED_TEST(CrossLazyLoad) {
11332 v8::HandleScope scope(CcTest::isolate());
11333 LocalContext other;
11334 LocalContext current;
11336 Local<String> token = v8_str("<security token>");
11337 other->SetSecurityToken(token);
11338 current->SetSecurityToken(token);
11340 // Set up reference from current to other.
11341 current->Global()->Set(v8_str("other"), other->Global());
11343 // Trigger lazy loading in other context.
11344 Local<Script> script = v8_compile("other.eval('new Date(42)')");
11345 Local<Value> value = script->Run();
11346 CHECK_EQ(42.0, value->NumberValue());
11350 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
11351 ApiTestFuzzer::Fuzz();
11352 if (args.IsConstructCall()) {
11353 if (args[0]->IsInt32()) {
11354 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value()));
11359 args.GetReturnValue().Set(args[0]);
11363 static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
11364 args.GetReturnValue().Set(args.This());
11368 // Test that a call handler can be set for objects which will allow
11369 // non-function objects created through the API to be called as
11371 THREADED_TEST(CallAsFunction) {
11372 LocalContext context;
11373 v8::Isolate* isolate = context->GetIsolate();
11374 v8::HandleScope scope(isolate);
11376 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11377 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11378 instance_template->SetCallAsFunctionHandler(call_as_function);
11379 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11380 context->Global()->Set(v8_str("obj"), instance);
11381 v8::TryCatch try_catch;
11382 Local<Value> value;
11383 CHECK(!try_catch.HasCaught());
11385 value = CompileRun("obj(42)");
11386 CHECK(!try_catch.HasCaught());
11387 CHECK_EQ(42, value->Int32Value());
11389 value = CompileRun("(function(o){return o(49)})(obj)");
11390 CHECK(!try_catch.HasCaught());
11391 CHECK_EQ(49, value->Int32Value());
11393 // test special case of call as function
11394 value = CompileRun("[obj]['0'](45)");
11395 CHECK(!try_catch.HasCaught());
11396 CHECK_EQ(45, value->Int32Value());
11398 value = CompileRun("obj.call = Function.prototype.call;"
11399 "obj.call(null, 87)");
11400 CHECK(!try_catch.HasCaught());
11401 CHECK_EQ(87, value->Int32Value());
11403 // Regression tests for bug #1116356: Calling call through call/apply
11404 // must work for non-function receivers.
11405 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
11406 value = CompileRun(apply_99);
11407 CHECK(!try_catch.HasCaught());
11408 CHECK_EQ(99, value->Int32Value());
11410 const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
11411 value = CompileRun(call_17);
11412 CHECK(!try_catch.HasCaught());
11413 CHECK_EQ(17, value->Int32Value());
11415 // Check that the call-as-function handler can be called through
11417 value = CompileRun("new obj(43)");
11418 CHECK(!try_catch.HasCaught());
11419 CHECK_EQ(-43, value->Int32Value());
11421 // Check that the call-as-function handler can be called through
11423 v8::Handle<Value> args[] = { v8_num(28) };
11424 value = instance->CallAsFunction(instance, 1, args);
11425 CHECK(!try_catch.HasCaught());
11426 CHECK_EQ(28, value->Int32Value());
11429 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11430 Local<ObjectTemplate> instance_template(t->InstanceTemplate());
11431 USE(instance_template);
11432 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11433 context->Global()->Set(v8_str("obj2"), instance);
11434 v8::TryCatch try_catch;
11435 Local<Value> value;
11436 CHECK(!try_catch.HasCaught());
11438 // Call an object without call-as-function handler through the JS
11439 value = CompileRun("obj2(28)");
11440 CHECK(value.IsEmpty());
11441 CHECK(try_catch.HasCaught());
11442 String::Utf8Value exception_value1(try_catch.Exception());
11443 // TODO(verwaest): Better message
11444 CHECK_EQ("TypeError: object is not a function",
11445 *exception_value1);
11448 // Call an object without call-as-function handler through the API
11449 value = CompileRun("obj2(28)");
11450 v8::Handle<Value> args[] = { v8_num(28) };
11451 value = instance->CallAsFunction(instance, 1, args);
11452 CHECK(value.IsEmpty());
11453 CHECK(try_catch.HasCaught());
11454 String::Utf8Value exception_value2(try_catch.Exception());
11455 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2);
11459 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11460 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11461 instance_template->SetCallAsFunctionHandler(ThrowValue);
11462 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11463 context->Global()->Set(v8_str("obj3"), instance);
11464 v8::TryCatch try_catch;
11465 Local<Value> value;
11466 CHECK(!try_catch.HasCaught());
11468 // Catch the exception which is thrown by call-as-function handler
11469 value = CompileRun("obj3(22)");
11470 CHECK(try_catch.HasCaught());
11471 String::Utf8Value exception_value1(try_catch.Exception());
11472 CHECK_EQ("22", *exception_value1);
11475 v8::Handle<Value> args[] = { v8_num(23) };
11476 value = instance->CallAsFunction(instance, 1, args);
11477 CHECK(try_catch.HasCaught());
11478 String::Utf8Value exception_value2(try_catch.Exception());
11479 CHECK_EQ("23", *exception_value2);
11483 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
11484 Local<ObjectTemplate> instance_template = t->InstanceTemplate();
11485 instance_template->SetCallAsFunctionHandler(ReturnThis);
11486 Local<v8::Object> instance = t->GetFunction()->NewInstance();
11488 Local<v8::Value> a1 =
11489 instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11490 CHECK(a1->StrictEquals(instance));
11491 Local<v8::Value> a2 =
11492 instance->CallAsFunction(v8::Null(isolate), 0, NULL);
11493 CHECK(a2->StrictEquals(instance));
11494 Local<v8::Value> a3 =
11495 instance->CallAsFunction(v8_num(42), 0, NULL);
11496 CHECK(a3->StrictEquals(instance));
11497 Local<v8::Value> a4 =
11498 instance->CallAsFunction(v8_str("hello"), 0, NULL);
11499 CHECK(a4->StrictEquals(instance));
11500 Local<v8::Value> a5 =
11501 instance->CallAsFunction(v8::True(isolate), 0, NULL);
11502 CHECK(a5->StrictEquals(instance));
11506 "function ReturnThisSloppy() {"
11509 "function ReturnThisStrict() {"
11513 Local<Function> ReturnThisSloppy =
11514 Local<Function>::Cast(
11515 context->Global()->Get(v8_str("ReturnThisSloppy")));
11516 Local<Function> ReturnThisStrict =
11517 Local<Function>::Cast(
11518 context->Global()->Get(v8_str("ReturnThisStrict")));
11520 Local<v8::Value> a1 =
11521 ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11522 CHECK(a1->StrictEquals(context->Global()));
11523 Local<v8::Value> a2 =
11524 ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
11525 CHECK(a2->StrictEquals(context->Global()));
11526 Local<v8::Value> a3 =
11527 ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
11528 CHECK(a3->IsNumberObject());
11529 CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
11530 Local<v8::Value> a4 =
11531 ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
11532 CHECK(a4->IsStringObject());
11533 CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
11534 Local<v8::Value> a5 =
11535 ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
11536 CHECK(a5->IsBooleanObject());
11537 CHECK(a5.As<v8::BooleanObject>()->ValueOf());
11539 Local<v8::Value> a6 =
11540 ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
11541 CHECK(a6->IsUndefined());
11542 Local<v8::Value> a7 =
11543 ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
11544 CHECK(a7->IsNull());
11545 Local<v8::Value> a8 =
11546 ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
11547 CHECK(a8->StrictEquals(v8_num(42)));
11548 Local<v8::Value> a9 =
11549 ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
11550 CHECK(a9->StrictEquals(v8_str("hello")));
11551 Local<v8::Value> a10 =
11552 ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
11553 CHECK(a10->StrictEquals(v8::True(isolate)));
11558 // Check whether a non-function object is callable.
11559 THREADED_TEST(CallableObject) {
11560 LocalContext context;
11561 v8::Isolate* isolate = context->GetIsolate();
11562 v8::HandleScope scope(isolate);
11564 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11565 instance_template->SetCallAsFunctionHandler(call_as_function);
11566 Local<Object> instance = instance_template->NewInstance();
11567 v8::TryCatch try_catch;
11569 CHECK(instance->IsCallable());
11570 CHECK(!try_catch.HasCaught());
11573 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(isolate);
11574 Local<Object> instance = instance_template->NewInstance();
11575 v8::TryCatch try_catch;
11577 CHECK(!instance->IsCallable());
11578 CHECK(!try_catch.HasCaught());
11581 { Local<FunctionTemplate> function_template =
11582 FunctionTemplate::New(isolate, call_as_function);
11583 Local<Function> function = function_template->GetFunction();
11584 Local<Object> instance = function;
11585 v8::TryCatch try_catch;
11587 CHECK(instance->IsCallable());
11588 CHECK(!try_catch.HasCaught());
11591 { Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
11592 Local<Function> function = function_template->GetFunction();
11593 Local<Object> instance = function;
11594 v8::TryCatch try_catch;
11596 CHECK(instance->IsCallable());
11597 CHECK(!try_catch.HasCaught());
11602 static int Recurse(v8::Isolate* isolate, int depth, int iterations) {
11603 v8::HandleScope scope(isolate);
11604 if (depth == 0) return v8::HandleScope::NumberOfHandles(isolate);
11605 for (int i = 0; i < iterations; i++) {
11606 Local<v8::Number> n(v8::Integer::New(isolate, 42));
11608 return Recurse(isolate, depth - 1, iterations);
11612 THREADED_TEST(HandleIteration) {
11613 static const int kIterations = 500;
11614 static const int kNesting = 200;
11615 LocalContext context;
11616 v8::Isolate* isolate = context->GetIsolate();
11617 v8::HandleScope scope0(isolate);
11618 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11620 v8::HandleScope scope1(isolate);
11621 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11622 for (int i = 0; i < kIterations; i++) {
11623 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11624 CHECK_EQ(i + 1, v8::HandleScope::NumberOfHandles(isolate));
11627 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11629 v8::HandleScope scope2(CcTest::isolate());
11630 for (int j = 0; j < kIterations; j++) {
11631 Local<v8::Number> n(v8::Integer::New(CcTest::isolate(), 42));
11632 CHECK_EQ(j + 1 + kIterations,
11633 v8::HandleScope::NumberOfHandles(isolate));
11636 CHECK_EQ(kIterations, v8::HandleScope::NumberOfHandles(isolate));
11638 CHECK_EQ(0, v8::HandleScope::NumberOfHandles(isolate));
11639 CHECK_EQ(kNesting * kIterations, Recurse(isolate, kNesting, kIterations));
11643 static void InterceptorHasOwnPropertyGetter(
11644 Local<String> name,
11645 const v8::PropertyCallbackInfo<v8::Value>& info) {
11646 ApiTestFuzzer::Fuzz();
11650 THREADED_TEST(InterceptorHasOwnProperty) {
11651 LocalContext context;
11652 v8::Isolate* isolate = context->GetIsolate();
11653 v8::HandleScope scope(isolate);
11654 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11655 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11656 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
11657 Local<Function> function = fun_templ->GetFunction();
11658 context->Global()->Set(v8_str("constructor"), function);
11659 v8::Handle<Value> value = CompileRun(
11660 "var o = new constructor();"
11661 "o.hasOwnProperty('ostehaps');");
11662 CHECK_EQ(false, value->BooleanValue());
11663 value = CompileRun(
11665 "o.hasOwnProperty('ostehaps');");
11666 CHECK_EQ(true, value->BooleanValue());
11667 value = CompileRun(
11668 "var p = new constructor();"
11669 "p.hasOwnProperty('ostehaps');");
11670 CHECK_EQ(false, value->BooleanValue());
11674 static void InterceptorHasOwnPropertyGetterGC(
11675 Local<String> name,
11676 const v8::PropertyCallbackInfo<v8::Value>& info) {
11677 ApiTestFuzzer::Fuzz();
11678 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
11682 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) {
11683 LocalContext context;
11684 v8::Isolate* isolate = context->GetIsolate();
11685 v8::HandleScope scope(isolate);
11686 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
11687 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
11688 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
11689 Local<Function> function = fun_templ->GetFunction();
11690 context->Global()->Set(v8_str("constructor"), function);
11691 // Let's first make some stuff so we can be sure to get a good GC.
11693 "function makestr(size) {"
11695 " case 1: return 'f';"
11696 " case 2: return 'fo';"
11697 " case 3: return 'foo';"
11699 " return makestr(size >> 1) + makestr((size + 1) >> 1);"
11701 "var x = makestr(12345);"
11702 "x = makestr(31415);"
11703 "x = makestr(23456);");
11704 v8::Handle<Value> value = CompileRun(
11705 "var o = new constructor();"
11706 "o.__proto__ = new String(x);"
11707 "o.hasOwnProperty('ostehaps');");
11708 CHECK_EQ(false, value->BooleanValue());
11712 typedef void (*NamedPropertyGetter)(
11713 Local<String> property,
11714 const v8::PropertyCallbackInfo<v8::Value>& info);
11717 static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
11718 const char* source,
11720 v8::Isolate* isolate = CcTest::isolate();
11721 v8::HandleScope scope(isolate);
11722 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11723 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
11724 LocalContext context;
11725 context->Global()->Set(v8_str("o"), templ->NewInstance());
11726 v8::Handle<Value> value = CompileRun(source);
11727 CHECK_EQ(expected, value->Int32Value());
11731 static void InterceptorLoadICGetter(
11732 Local<String> name,
11733 const v8::PropertyCallbackInfo<v8::Value>& info) {
11734 ApiTestFuzzer::Fuzz();
11735 v8::Isolate* isolate = CcTest::isolate();
11736 CHECK_EQ(isolate, info.GetIsolate());
11737 CHECK_EQ(v8_str("data"), info.Data());
11738 CHECK_EQ(v8_str("x"), name);
11739 info.GetReturnValue().Set(v8::Integer::New(isolate, 42));
11743 // This test should hit the load IC for the interceptor case.
11744 THREADED_TEST(InterceptorLoadIC) {
11745 CheckInterceptorLoadIC(InterceptorLoadICGetter,
11747 "for (var i = 0; i < 1000; i++) {"
11754 // Below go several tests which verify that JITing for various
11755 // configurations of interceptor and explicit fields works fine
11756 // (those cases are special cased to get better performance).
11758 static void InterceptorLoadXICGetter(
11759 Local<String> name,
11760 const v8::PropertyCallbackInfo<v8::Value>& info) {
11761 ApiTestFuzzer::Fuzz();
11762 info.GetReturnValue().Set(
11763 v8_str("x")->Equals(name) ?
11764 v8::Handle<v8::Value>(v8::Integer::New(info.GetIsolate(), 42)) :
11765 v8::Handle<v8::Value>());
11769 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) {
11770 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11773 "for (var i = 0; i < 1000; i++) {"
11780 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) {
11781 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11783 "o.__proto__ = { 'y': 239 };"
11784 "for (var i = 0; i < 1000; i++) {"
11785 " result = o.y + o.x;"
11791 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) {
11792 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11794 "o.__proto__.y = 239;"
11795 "for (var i = 0; i < 1000; i++) {"
11796 " result = o.y + o.x;"
11802 THREADED_TEST(InterceptorLoadICUndefined) {
11803 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11805 "for (var i = 0; i < 1000; i++) {"
11806 " result = (o.y == undefined) ? 239 : 42;"
11812 THREADED_TEST(InterceptorLoadICWithOverride) {
11813 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11814 "fst = new Object(); fst.__proto__ = o;"
11815 "snd = new Object(); snd.__proto__ = fst;"
11817 "for (var i = 0; i < 1000; i++) {"
11818 " result1 = snd.x;"
11822 "for (var i = 0; i < 1000; i++) {"
11825 "result + result1",
11830 // Test the case when we stored field into
11831 // a stub, but interceptor produced value on its own.
11832 THREADED_TEST(InterceptorLoadICFieldNotNeeded) {
11833 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11834 "proto = new Object();"
11835 "o.__proto__ = proto;"
11837 "for (var i = 0; i < 1000; i++) {"
11839 // Now it should be ICed and keep a reference to x defined on proto
11842 "for (var i = 0; i < 1000; i++) {"
11850 // Test the case when we stored field into
11851 // a stub, but it got invalidated later on.
11852 THREADED_TEST(InterceptorLoadICInvalidatedField) {
11853 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11854 "proto1 = new Object();"
11855 "proto2 = new Object();"
11856 "o.__proto__ = proto1;"
11857 "proto1.__proto__ = proto2;"
11859 "for (var i = 0; i < 1000; i++) {"
11861 // Now it should be ICed and keep a reference to y defined on proto2
11865 "for (var i = 0; i < 1000; i++) {"
11873 static int interceptor_load_not_handled_calls = 0;
11874 static void InterceptorLoadNotHandled(
11875 Local<String> name,
11876 const v8::PropertyCallbackInfo<v8::Value>& info) {
11877 ++interceptor_load_not_handled_calls;
11881 // Test how post-interceptor lookups are done in the non-cacheable
11882 // case: the interceptor should not be invoked during this lookup.
11883 THREADED_TEST(InterceptorLoadICPostInterceptor) {
11884 interceptor_load_not_handled_calls = 0;
11885 CheckInterceptorLoadIC(InterceptorLoadNotHandled,
11886 "receiver = new Object();"
11887 "receiver.__proto__ = o;"
11888 "proto = new Object();"
11889 "/* Make proto a slow-case object. */"
11890 "for (var i = 0; i < 1000; i++) {"
11891 " proto[\"xxxxxxxx\" + i] = [];"
11894 "o.__proto__ = proto;"
11896 "for (var i = 0; i < 1000; i++) {"
11897 " result += receiver.x;"
11901 CHECK_EQ(1000, interceptor_load_not_handled_calls);
11905 // Test the case when we stored field into
11906 // a stub, but it got invalidated later on due to override on
11907 // global object which is between interceptor and fields' holders.
11908 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) {
11909 CheckInterceptorLoadIC(InterceptorLoadXICGetter,
11910 "o.__proto__ = this;" // set a global to be a proto of o.
11911 "this.__proto__.y = 239;"
11912 "for (var i = 0; i < 10; i++) {"
11913 " if (o.y != 239) throw 'oops: ' + o.y;"
11914 // Now it should be ICed and keep a reference to y defined on field_holder.
11916 "this.y = 42;" // Assign on a global.
11918 "for (var i = 0; i < 10; i++) {"
11926 static void SetOnThis(Local<String> name,
11927 Local<Value> value,
11928 const v8::PropertyCallbackInfo<void>& info) {
11929 Local<Object>::Cast(info.This())->ForceSet(name, value);
11933 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) {
11934 v8::Isolate* isolate = CcTest::isolate();
11935 v8::HandleScope scope(isolate);
11936 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
11937 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11938 templ->SetAccessor(v8_str("y"), Return239Callback);
11939 LocalContext context;
11940 context->Global()->Set(v8_str("o"), templ->NewInstance());
11942 // Check the case when receiver and interceptor's holder
11943 // are the same objects.
11944 v8::Handle<Value> value = CompileRun(
11946 "for (var i = 0; i < 7; i++) {"
11949 CHECK_EQ(239, value->Int32Value());
11951 // Check the case when interceptor's holder is in proto chain
11953 value = CompileRun(
11954 "r = { __proto__: o };"
11956 "for (var i = 0; i < 7; i++) {"
11959 CHECK_EQ(239, value->Int32Value());
11963 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) {
11964 v8::Isolate* isolate = CcTest::isolate();
11965 v8::HandleScope scope(isolate);
11966 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
11967 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
11968 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
11969 templ_p->SetAccessor(v8_str("y"), Return239Callback);
11971 LocalContext context;
11972 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
11973 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
11975 // Check the case when receiver and interceptor's holder
11976 // are the same objects.
11977 v8::Handle<Value> value = CompileRun(
11980 "for (var i = 0; i < 7; i++) {"
11981 " result = o.x + o.y;"
11983 CHECK_EQ(239 + 42, value->Int32Value());
11985 // Check the case when interceptor's holder is in proto chain
11987 value = CompileRun(
11988 "r = { __proto__: o };"
11990 "for (var i = 0; i < 7; i++) {"
11991 " result = r.x + r.y;"
11993 CHECK_EQ(239 + 42, value->Int32Value());
11997 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) {
11998 v8::Isolate* isolate = CcTest::isolate();
11999 v8::HandleScope scope(isolate);
12000 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12001 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12002 templ->SetAccessor(v8_str("y"), Return239Callback);
12004 LocalContext context;
12005 context->Global()->Set(v8_str("o"), templ->NewInstance());
12007 v8::Handle<Value> value = CompileRun(
12008 "fst = new Object(); fst.__proto__ = o;"
12009 "snd = new Object(); snd.__proto__ = fst;"
12011 "for (var i = 0; i < 7; i++) {"
12012 " result1 = snd.x;"
12016 "for (var i = 0; i < 7; i++) {"
12019 "result + result1");
12020 CHECK_EQ(239 + 42, value->Int32Value());
12024 // Test the case when we stored callback into
12025 // a stub, but interceptor produced value on its own.
12026 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) {
12027 v8::Isolate* isolate = CcTest::isolate();
12028 v8::HandleScope scope(isolate);
12029 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12030 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12031 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12032 templ_p->SetAccessor(v8_str("y"), Return239Callback);
12034 LocalContext context;
12035 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12036 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12038 v8::Handle<Value> value = CompileRun(
12040 "for (var i = 0; i < 7; i++) {"
12042 // Now it should be ICed and keep a reference to x defined on p
12045 "for (var i = 0; i < 7; i++) {"
12049 CHECK_EQ(42 * 7, value->Int32Value());
12053 // Test the case when we stored callback into
12054 // a stub, but it got invalidated later on.
12055 THREADED_TEST(InterceptorLoadICInvalidatedCallback) {
12056 v8::Isolate* isolate = CcTest::isolate();
12057 v8::HandleScope scope(isolate);
12058 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12059 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12060 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12061 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
12063 LocalContext context;
12064 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12065 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12067 v8::Handle<Value> value = CompileRun(
12068 "inbetween = new Object();"
12069 "o.__proto__ = inbetween;"
12070 "inbetween.__proto__ = p;"
12071 "for (var i = 0; i < 10; i++) {"
12073 // Now it should be ICed and keep a reference to y defined on p
12075 "inbetween.y = 42;"
12077 "for (var i = 0; i < 10; i++) {"
12081 CHECK_EQ(42 * 10, value->Int32Value());
12085 // Test the case when we stored callback into
12086 // a stub, but it got invalidated later on due to override on
12087 // global object which is between interceptor and callbacks' holders.
12088 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) {
12089 v8::Isolate* isolate = CcTest::isolate();
12090 v8::HandleScope scope(isolate);
12091 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12092 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12093 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
12094 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
12096 LocalContext context;
12097 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12098 context->Global()->Set(v8_str("p"), templ_p->NewInstance());
12100 v8::Handle<Value> value = CompileRun(
12101 "o.__proto__ = this;"
12102 "this.__proto__ = p;"
12103 "for (var i = 0; i < 10; i++) {"
12104 " if (o.y != 239) throw 'oops: ' + o.y;"
12105 // Now it should be ICed and keep a reference to y defined on p
12109 "for (var i = 0; i < 10; i++) {"
12113 CHECK_EQ(42 * 10, value->Int32Value());
12117 static void InterceptorLoadICGetter0(
12118 Local<String> name,
12119 const v8::PropertyCallbackInfo<v8::Value>& info) {
12120 ApiTestFuzzer::Fuzz();
12121 CHECK(v8_str("x")->Equals(name));
12122 info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
12126 THREADED_TEST(InterceptorReturningZero) {
12127 CheckInterceptorLoadIC(InterceptorLoadICGetter0,
12128 "o.x == undefined ? 1 : 0",
12133 static void InterceptorStoreICSetter(
12135 Local<Value> value,
12136 const v8::PropertyCallbackInfo<v8::Value>& info) {
12137 CHECK(v8_str("x")->Equals(key));
12138 CHECK_EQ(42, value->Int32Value());
12139 info.GetReturnValue().Set(value);
12143 // This test should hit the store IC for the interceptor case.
12144 THREADED_TEST(InterceptorStoreIC) {
12145 v8::Isolate* isolate = CcTest::isolate();
12146 v8::HandleScope scope(isolate);
12147 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12148 templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
12149 InterceptorStoreICSetter,
12150 0, 0, 0, v8_str("data"));
12151 LocalContext context;
12152 context->Global()->Set(v8_str("o"), templ->NewInstance());
12154 "for (var i = 0; i < 1000; i++) {"
12160 THREADED_TEST(InterceptorStoreICWithNoSetter) {
12161 v8::Isolate* isolate = CcTest::isolate();
12162 v8::HandleScope scope(isolate);
12163 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12164 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
12165 LocalContext context;
12166 context->Global()->Set(v8_str("o"), templ->NewInstance());
12167 v8::Handle<Value> value = CompileRun(
12168 "for (var i = 0; i < 1000; i++) {"
12172 CHECK_EQ(239 + 42, value->Int32Value());
12178 v8::Handle<Value> call_ic_function;
12179 v8::Handle<Value> call_ic_function2;
12180 v8::Handle<Value> call_ic_function3;
12182 static void InterceptorCallICGetter(
12183 Local<String> name,
12184 const v8::PropertyCallbackInfo<v8::Value>& info) {
12185 ApiTestFuzzer::Fuzz();
12186 CHECK(v8_str("x")->Equals(name));
12187 info.GetReturnValue().Set(call_ic_function);
12191 // This test should hit the call IC for the interceptor case.
12192 THREADED_TEST(InterceptorCallIC) {
12193 v8::Isolate* isolate = CcTest::isolate();
12194 v8::HandleScope scope(isolate);
12195 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12196 templ->SetNamedPropertyHandler(InterceptorCallICGetter);
12197 LocalContext context;
12198 context->Global()->Set(v8_str("o"), templ->NewInstance());
12200 v8_compile("function f(x) { return x + 1; }; f")->Run();
12201 v8::Handle<Value> value = CompileRun(
12203 "for (var i = 0; i < 1000; i++) {"
12204 " result = o.x(41);"
12206 CHECK_EQ(42, value->Int32Value());
12210 // This test checks that if interceptor doesn't provide
12211 // a value, we can fetch regular value.
12212 THREADED_TEST(InterceptorCallICSeesOthers) {
12213 v8::Isolate* isolate = CcTest::isolate();
12214 v8::HandleScope scope(isolate);
12215 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12216 templ->SetNamedPropertyHandler(NoBlockGetterX);
12217 LocalContext context;
12218 context->Global()->Set(v8_str("o"), templ->NewInstance());
12219 v8::Handle<Value> value = CompileRun(
12220 "o.x = function f(x) { return x + 1; };"
12222 "for (var i = 0; i < 7; i++) {"
12223 " result = o.x(41);"
12225 CHECK_EQ(42, value->Int32Value());
12229 static v8::Handle<Value> call_ic_function4;
12230 static void InterceptorCallICGetter4(
12231 Local<String> name,
12232 const v8::PropertyCallbackInfo<v8::Value>& info) {
12233 ApiTestFuzzer::Fuzz();
12234 CHECK(v8_str("x")->Equals(name));
12235 info.GetReturnValue().Set(call_ic_function4);
12239 // This test checks that if interceptor provides a function,
12240 // even if we cached shadowed variant, interceptor's function
12242 THREADED_TEST(InterceptorCallICCacheableNotNeeded) {
12243 v8::Isolate* isolate = CcTest::isolate();
12244 v8::HandleScope scope(isolate);
12245 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12246 templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
12247 LocalContext context;
12248 context->Global()->Set(v8_str("o"), templ->NewInstance());
12249 call_ic_function4 =
12250 v8_compile("function f(x) { return x - 1; }; f")->Run();
12251 v8::Handle<Value> value = CompileRun(
12252 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };"
12254 "for (var i = 0; i < 1000; i++) {"
12255 " result = o.x(42);"
12257 CHECK_EQ(41, value->Int32Value());
12261 // Test the case when we stored cacheable lookup into
12262 // a stub, but it got invalidated later on
12263 THREADED_TEST(InterceptorCallICInvalidatedCacheable) {
12264 v8::Isolate* isolate = CcTest::isolate();
12265 v8::HandleScope scope(isolate);
12266 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12267 templ->SetNamedPropertyHandler(NoBlockGetterX);
12268 LocalContext context;
12269 context->Global()->Set(v8_str("o"), templ->NewInstance());
12270 v8::Handle<Value> value = CompileRun(
12271 "proto1 = new Object();"
12272 "proto2 = new Object();"
12273 "o.__proto__ = proto1;"
12274 "proto1.__proto__ = proto2;"
12275 "proto2.y = function(x) { return x + 1; };"
12276 // Invoke it many times to compile a stub
12277 "for (var i = 0; i < 7; i++) {"
12280 "proto1.y = function(x) { return x - 1; };"
12282 "for (var i = 0; i < 7; i++) {"
12283 " result += o.y(42);"
12285 CHECK_EQ(41 * 7, value->Int32Value());
12289 // This test checks that if interceptor doesn't provide a function,
12290 // cached constant function is used
12291 THREADED_TEST(InterceptorCallICConstantFunctionUsed) {
12292 v8::Isolate* isolate = CcTest::isolate();
12293 v8::HandleScope scope(isolate);
12294 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12295 templ->SetNamedPropertyHandler(NoBlockGetterX);
12296 LocalContext context;
12297 context->Global()->Set(v8_str("o"), templ->NewInstance());
12298 v8::Handle<Value> value = CompileRun(
12299 "function inc(x) { return x + 1; };"
12303 "for (var i = 0; i < 1000; i++) {"
12304 " result = o.x(42);"
12306 CHECK_EQ(43, value->Int32Value());
12310 static v8::Handle<Value> call_ic_function5;
12311 static void InterceptorCallICGetter5(
12312 Local<String> name,
12313 const v8::PropertyCallbackInfo<v8::Value>& info) {
12314 ApiTestFuzzer::Fuzz();
12315 if (v8_str("x")->Equals(name))
12316 info.GetReturnValue().Set(call_ic_function5);
12320 // This test checks that if interceptor provides a function,
12321 // even if we cached constant function, interceptor's function
12323 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) {
12324 v8::Isolate* isolate = CcTest::isolate();
12325 v8::HandleScope scope(isolate);
12326 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12327 templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
12328 LocalContext context;
12329 context->Global()->Set(v8_str("o"), templ->NewInstance());
12330 call_ic_function5 =
12331 v8_compile("function f(x) { return x - 1; }; f")->Run();
12332 v8::Handle<Value> value = CompileRun(
12333 "function inc(x) { return x + 1; };"
12337 "for (var i = 0; i < 1000; i++) {"
12338 " result = o.x(42);"
12340 CHECK_EQ(41, value->Int32Value());
12344 static v8::Handle<Value> call_ic_function6;
12345 static void InterceptorCallICGetter6(
12346 Local<String> name,
12347 const v8::PropertyCallbackInfo<v8::Value>& info) {
12348 ApiTestFuzzer::Fuzz();
12349 if (v8_str("x")->Equals(name))
12350 info.GetReturnValue().Set(call_ic_function6);
12354 // Same test as above, except the code is wrapped in a function
12355 // to test the optimized compiler.
12356 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) {
12357 i::FLAG_allow_natives_syntax = true;
12358 v8::Isolate* isolate = CcTest::isolate();
12359 v8::HandleScope scope(isolate);
12360 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12361 templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
12362 LocalContext context;
12363 context->Global()->Set(v8_str("o"), templ->NewInstance());
12364 call_ic_function6 =
12365 v8_compile("function f(x) { return x - 1; }; f")->Run();
12366 v8::Handle<Value> value = CompileRun(
12367 "function inc(x) { return x + 1; };"
12370 "function test() {"
12372 " for (var i = 0; i < 1000; i++) {"
12373 " result = o.x(42);"
12380 "%OptimizeFunctionOnNextCall(test);"
12382 CHECK_EQ(41, value->Int32Value());
12386 // Test the case when we stored constant function into
12387 // a stub, but it got invalidated later on
12388 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) {
12389 v8::Isolate* isolate = CcTest::isolate();
12390 v8::HandleScope scope(isolate);
12391 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12392 templ->SetNamedPropertyHandler(NoBlockGetterX);
12393 LocalContext context;
12394 context->Global()->Set(v8_str("o"), templ->NewInstance());
12395 v8::Handle<Value> value = CompileRun(
12396 "function inc(x) { return x + 1; };"
12398 "proto1 = new Object();"
12399 "proto2 = new Object();"
12400 "o.__proto__ = proto1;"
12401 "proto1.__proto__ = proto2;"
12403 // Invoke it many times to compile a stub
12404 "for (var i = 0; i < 7; i++) {"
12407 "proto1.y = function(x) { return x - 1; };"
12409 "for (var i = 0; i < 7; i++) {"
12410 " result += o.y(42);"
12412 CHECK_EQ(41 * 7, value->Int32Value());
12416 // Test the case when we stored constant function into
12417 // a stub, but it got invalidated later on due to override on
12418 // global object which is between interceptor and constant function' holders.
12419 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) {
12420 v8::Isolate* isolate = CcTest::isolate();
12421 v8::HandleScope scope(isolate);
12422 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
12423 templ->SetNamedPropertyHandler(NoBlockGetterX);
12424 LocalContext context;
12425 context->Global()->Set(v8_str("o"), templ->NewInstance());
12426 v8::Handle<Value> value = CompileRun(
12427 "function inc(x) { return x + 1; };"
12429 "o.__proto__ = this;"
12430 "this.__proto__.y = inc;"
12431 // Invoke it many times to compile a stub
12432 "for (var i = 0; i < 7; i++) {"
12433 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);"
12435 "this.y = function(x) { return x - 1; };"
12437 "for (var i = 0; i < 7; i++) {"
12438 " result += o.y(42);"
12440 CHECK_EQ(41 * 7, value->Int32Value());
12444 // Test the case when actual function to call sits on global object.
12445 THREADED_TEST(InterceptorCallICCachedFromGlobal) {
12446 v8::Isolate* isolate = CcTest::isolate();
12447 v8::HandleScope scope(isolate);
12448 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
12449 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
12451 LocalContext context;
12452 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
12454 v8::Handle<Value> value = CompileRun(
12456 " o.__proto__ = this;"
12457 " for (var i = 0; i < 10; i++) {"
12458 " var v = o.parseFloat('239');"
12459 " if (v != 239) throw v;"
12460 // Now it should be ICed and keep a reference to parseFloat.
12463 " for (var i = 0; i < 10; i++) {"
12464 " result += o.parseFloat('239');"
12470 CHECK_EQ(239 * 10, value->Int32Value());
12473 static void InterceptorCallICFastApi(
12474 Local<String> name,
12475 const v8::PropertyCallbackInfo<v8::Value>& info) {
12476 ApiTestFuzzer::Fuzz();
12477 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
12479 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
12481 if ((*call_count) % 20 == 0) {
12482 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
12486 static void FastApiCallback_TrivialSignature(
12487 const v8::FunctionCallbackInfo<v8::Value>& args) {
12488 ApiTestFuzzer::Fuzz();
12489 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
12490 v8::Isolate* isolate = CcTest::isolate();
12491 CHECK_EQ(isolate, args.GetIsolate());
12492 CHECK_EQ(args.This(), args.Holder());
12493 CHECK(args.Data()->Equals(v8_str("method_data")));
12494 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12497 static void FastApiCallback_SimpleSignature(
12498 const v8::FunctionCallbackInfo<v8::Value>& args) {
12499 ApiTestFuzzer::Fuzz();
12500 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
12501 v8::Isolate* isolate = CcTest::isolate();
12502 CHECK_EQ(isolate, args.GetIsolate());
12503 CHECK_EQ(args.This()->GetPrototype(), args.Holder());
12504 CHECK(args.Data()->Equals(v8_str("method_data")));
12505 // Note, we're using HasRealNamedProperty instead of Has to avoid
12506 // invoking the interceptor again.
12507 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo")));
12508 args.GetReturnValue().Set(args[0]->Int32Value() + 1);
12512 // Helper to maximize the odds of object moving.
12513 static void GenerateSomeGarbage() {
12516 "for (var i = 0; i < 1000; i++) {"
12517 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];"
12519 "garbage = undefined;");
12523 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
12524 static int count = 0;
12525 if (count++ % 3 == 0) {
12526 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12527 // This should move the stub
12528 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed
12533 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) {
12534 LocalContext context;
12535 v8::Isolate* isolate = context->GetIsolate();
12536 v8::HandleScope scope(isolate);
12537 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12538 v8::ObjectTemplate::New(isolate);
12539 nativeobject_templ->Set(isolate, "callback",
12540 v8::FunctionTemplate::New(isolate,
12541 DirectApiCallback));
12542 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12543 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12544 // call the api function multiple times to ensure direct call stub creation.
12547 " for (var i = 1; i <= 30; i++) {"
12548 " nativeobject.callback();"
12555 void ThrowingDirectApiCallback(
12556 const v8::FunctionCallbackInfo<v8::Value>& args) {
12557 args.GetIsolate()->ThrowException(v8_str("g"));
12561 THREADED_TEST(CallICFastApi_DirectCall_Throw) {
12562 LocalContext context;
12563 v8::Isolate* isolate = context->GetIsolate();
12564 v8::HandleScope scope(isolate);
12565 v8::Handle<v8::ObjectTemplate> nativeobject_templ =
12566 v8::ObjectTemplate::New(isolate);
12567 nativeobject_templ->Set(isolate, "callback",
12568 v8::FunctionTemplate::New(isolate,
12569 ThrowingDirectApiCallback));
12570 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance();
12571 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj);
12572 // call the api function multiple times to ensure direct call stub creation.
12573 v8::Handle<Value> result = CompileRun(
12576 " for (var i = 1; i <= 5; i++) {"
12577 " try { nativeobject.callback(); } catch (e) { result += e; }"
12581 CHECK_EQ(v8_str("ggggg"), result);
12585 static Handle<Value> DoDirectGetter() {
12586 if (++p_getter_count % 3 == 0) {
12587 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
12588 GenerateSomeGarbage();
12590 return v8_str("Direct Getter Result");
12593 static void DirectGetterCallback(
12594 Local<String> name,
12595 const v8::PropertyCallbackInfo<v8::Value>& info) {
12596 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
12597 info.GetReturnValue().Set(DoDirectGetter());
12601 template<typename Accessor>
12602 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) {
12603 LocalContext context;
12604 v8::Isolate* isolate = context->GetIsolate();
12605 v8::HandleScope scope(isolate);
12606 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12607 obj->SetAccessor(v8_str("p1"), accessor);
12608 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12609 p_getter_count = 0;
12610 v8::Handle<v8::Value> result = CompileRun(
12612 " for (var i = 0; i < 30; i++) o1.p1;"
12616 CHECK_EQ(v8_str("Direct Getter Result"), result);
12617 CHECK_EQ(31, p_getter_count);
12621 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) {
12622 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback);
12626 void ThrowingDirectGetterCallback(
12627 Local<String> name,
12628 const v8::PropertyCallbackInfo<v8::Value>& info) {
12629 info.GetIsolate()->ThrowException(v8_str("g"));
12633 THREADED_TEST(LoadICFastApi_DirectCall_Throw) {
12634 LocalContext context;
12635 v8::Isolate* isolate = context->GetIsolate();
12636 v8::HandleScope scope(isolate);
12637 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(isolate);
12638 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback);
12639 context->Global()->Set(v8_str("o1"), obj->NewInstance());
12640 v8::Handle<Value> result = CompileRun(
12642 "for (var i = 0; i < 5; i++) {"
12643 " try { o1.p1; } catch (e) { result += e; }"
12646 CHECK_EQ(v8_str("ggggg"), result);
12650 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) {
12651 int interceptor_call_count = 0;
12652 v8::Isolate* isolate = CcTest::isolate();
12653 v8::HandleScope scope(isolate);
12654 v8::Handle<v8::FunctionTemplate> fun_templ =
12655 v8::FunctionTemplate::New(isolate);
12656 v8::Handle<v8::FunctionTemplate> method_templ =
12657 v8::FunctionTemplate::New(isolate,
12658 FastApiCallback_TrivialSignature,
12659 v8_str("method_data"),
12660 v8::Handle<v8::Signature>());
12661 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12662 proto_templ->Set(v8_str("method"), method_templ);
12663 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12664 templ->SetNamedPropertyHandler(
12665 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12666 v8::External::New(isolate, &interceptor_call_count));
12667 LocalContext context;
12668 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12669 GenerateSomeGarbage();
12670 context->Global()->Set(v8_str("o"), fun->NewInstance());
12673 "for (var i = 0; i < 100; i++) {"
12674 " result = o.method(41);"
12676 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12677 CHECK_EQ(100, interceptor_call_count);
12681 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) {
12682 int interceptor_call_count = 0;
12683 v8::Isolate* isolate = CcTest::isolate();
12684 v8::HandleScope scope(isolate);
12685 v8::Handle<v8::FunctionTemplate> fun_templ =
12686 v8::FunctionTemplate::New(isolate);
12687 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12688 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12689 v8::Signature::New(isolate, fun_templ));
12690 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12691 proto_templ->Set(v8_str("method"), method_templ);
12692 fun_templ->SetHiddenPrototype(true);
12693 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12694 templ->SetNamedPropertyHandler(
12695 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12696 v8::External::New(isolate, &interceptor_call_count));
12697 LocalContext context;
12698 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12699 GenerateSomeGarbage();
12700 context->Global()->Set(v8_str("o"), fun->NewInstance());
12703 "var receiver = {};"
12704 "receiver.__proto__ = o;"
12706 "for (var i = 0; i < 100; i++) {"
12707 " result = receiver.method(41);"
12709 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12710 CHECK_EQ(100, interceptor_call_count);
12714 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
12715 int interceptor_call_count = 0;
12716 v8::Isolate* isolate = CcTest::isolate();
12717 v8::HandleScope scope(isolate);
12718 v8::Handle<v8::FunctionTemplate> fun_templ =
12719 v8::FunctionTemplate::New(isolate);
12720 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12721 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12722 v8::Signature::New(isolate, fun_templ));
12723 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12724 proto_templ->Set(v8_str("method"), method_templ);
12725 fun_templ->SetHiddenPrototype(true);
12726 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12727 templ->SetNamedPropertyHandler(
12728 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12729 v8::External::New(isolate, &interceptor_call_count));
12730 LocalContext context;
12731 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12732 GenerateSomeGarbage();
12733 context->Global()->Set(v8_str("o"), fun->NewInstance());
12736 "var receiver = {};"
12737 "receiver.__proto__ = o;"
12739 "var saved_result = 0;"
12740 "for (var i = 0; i < 100; i++) {"
12741 " result = receiver.method(41);"
12743 " saved_result = result;"
12744 " receiver = {method: function(x) { return x - 1 }};"
12747 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12748 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12749 CHECK_GE(interceptor_call_count, 50);
12753 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
12754 int interceptor_call_count = 0;
12755 v8::Isolate* isolate = CcTest::isolate();
12756 v8::HandleScope scope(isolate);
12757 v8::Handle<v8::FunctionTemplate> fun_templ =
12758 v8::FunctionTemplate::New(isolate);
12759 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12760 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12761 v8::Signature::New(isolate, fun_templ));
12762 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12763 proto_templ->Set(v8_str("method"), method_templ);
12764 fun_templ->SetHiddenPrototype(true);
12765 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12766 templ->SetNamedPropertyHandler(
12767 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12768 v8::External::New(isolate, &interceptor_call_count));
12769 LocalContext context;
12770 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12771 GenerateSomeGarbage();
12772 context->Global()->Set(v8_str("o"), fun->NewInstance());
12775 "var receiver = {};"
12776 "receiver.__proto__ = o;"
12778 "var saved_result = 0;"
12779 "for (var i = 0; i < 100; i++) {"
12780 " result = receiver.method(41);"
12782 " saved_result = result;"
12783 " o.method = function(x) { return x - 1 };"
12786 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12787 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12788 CHECK_GE(interceptor_call_count, 50);
12792 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
12793 int interceptor_call_count = 0;
12794 v8::Isolate* isolate = CcTest::isolate();
12795 v8::HandleScope scope(isolate);
12796 v8::Handle<v8::FunctionTemplate> fun_templ =
12797 v8::FunctionTemplate::New(isolate);
12798 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12799 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12800 v8::Signature::New(isolate, fun_templ));
12801 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12802 proto_templ->Set(v8_str("method"), method_templ);
12803 fun_templ->SetHiddenPrototype(true);
12804 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12805 templ->SetNamedPropertyHandler(
12806 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12807 v8::External::New(isolate, &interceptor_call_count));
12808 LocalContext context;
12809 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12810 GenerateSomeGarbage();
12811 context->Global()->Set(v8_str("o"), fun->NewInstance());
12812 v8::TryCatch try_catch;
12815 "var receiver = {};"
12816 "receiver.__proto__ = o;"
12818 "var saved_result = 0;"
12819 "for (var i = 0; i < 100; i++) {"
12820 " result = receiver.method(41);"
12822 " saved_result = result;"
12826 CHECK(try_catch.HasCaught());
12827 // TODO(verwaest): Adjust message.
12828 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
12829 try_catch.Exception()->ToString());
12830 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12831 CHECK_GE(interceptor_call_count, 50);
12835 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
12836 int interceptor_call_count = 0;
12837 v8::Isolate* isolate = CcTest::isolate();
12838 v8::HandleScope scope(isolate);
12839 v8::Handle<v8::FunctionTemplate> fun_templ =
12840 v8::FunctionTemplate::New(isolate);
12841 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12842 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12843 v8::Signature::New(isolate, fun_templ));
12844 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12845 proto_templ->Set(v8_str("method"), method_templ);
12846 fun_templ->SetHiddenPrototype(true);
12847 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
12848 templ->SetNamedPropertyHandler(
12849 InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
12850 v8::External::New(isolate, &interceptor_call_count));
12851 LocalContext context;
12852 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12853 GenerateSomeGarbage();
12854 context->Global()->Set(v8_str("o"), fun->NewInstance());
12855 v8::TryCatch try_catch;
12858 "var receiver = {};"
12859 "receiver.__proto__ = o;"
12861 "var saved_result = 0;"
12862 "for (var i = 0; i < 100; i++) {"
12863 " result = receiver.method(41);"
12865 " saved_result = result;"
12866 " receiver = {method: receiver.method};"
12869 CHECK(try_catch.HasCaught());
12870 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
12871 try_catch.Exception()->ToString());
12872 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12873 CHECK_GE(interceptor_call_count, 50);
12877 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) {
12878 v8::Isolate* isolate = CcTest::isolate();
12879 v8::HandleScope scope(isolate);
12880 v8::Handle<v8::FunctionTemplate> fun_templ =
12881 v8::FunctionTemplate::New(isolate);
12882 v8::Handle<v8::FunctionTemplate> method_templ =
12883 v8::FunctionTemplate::New(isolate,
12884 FastApiCallback_TrivialSignature,
12885 v8_str("method_data"),
12886 v8::Handle<v8::Signature>());
12887 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12888 proto_templ->Set(v8_str("method"), method_templ);
12889 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12891 LocalContext context;
12892 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12893 GenerateSomeGarbage();
12894 context->Global()->Set(v8_str("o"), fun->NewInstance());
12897 "for (var i = 0; i < 100; i++) {"
12898 " result = o.method(41);"
12901 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12905 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) {
12906 v8::Isolate* isolate = CcTest::isolate();
12907 v8::HandleScope scope(isolate);
12908 v8::Handle<v8::FunctionTemplate> fun_templ =
12909 v8::FunctionTemplate::New(isolate);
12910 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12911 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12912 v8::Signature::New(isolate, fun_templ));
12913 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12914 proto_templ->Set(v8_str("method"), method_templ);
12915 fun_templ->SetHiddenPrototype(true);
12916 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12917 CHECK(!templ.IsEmpty());
12918 LocalContext context;
12919 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12920 GenerateSomeGarbage();
12921 context->Global()->Set(v8_str("o"), fun->NewInstance());
12924 "var receiver = {};"
12925 "receiver.__proto__ = o;"
12927 "for (var i = 0; i < 100; i++) {"
12928 " result = receiver.method(41);"
12931 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value());
12935 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) {
12936 v8::Isolate* isolate = CcTest::isolate();
12937 v8::HandleScope scope(isolate);
12938 v8::Handle<v8::FunctionTemplate> fun_templ =
12939 v8::FunctionTemplate::New(isolate);
12940 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12941 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12942 v8::Signature::New(isolate, fun_templ));
12943 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12944 proto_templ->Set(v8_str("method"), method_templ);
12945 fun_templ->SetHiddenPrototype(true);
12946 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12947 CHECK(!templ.IsEmpty());
12948 LocalContext context;
12949 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12950 GenerateSomeGarbage();
12951 context->Global()->Set(v8_str("o"), fun->NewInstance());
12954 "var receiver = {};"
12955 "receiver.__proto__ = o;"
12957 "var saved_result = 0;"
12958 "for (var i = 0; i < 100; i++) {"
12959 " result = receiver.method(41);"
12961 " saved_result = result;"
12962 " receiver = {method: function(x) { return x - 1 }};"
12965 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value());
12966 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
12970 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) {
12971 v8::Isolate* isolate = CcTest::isolate();
12972 v8::HandleScope scope(isolate);
12973 v8::Handle<v8::FunctionTemplate> fun_templ =
12974 v8::FunctionTemplate::New(isolate);
12975 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
12976 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
12977 v8::Signature::New(isolate, fun_templ));
12978 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
12979 proto_templ->Set(v8_str("method"), method_templ);
12980 fun_templ->SetHiddenPrototype(true);
12981 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
12982 CHECK(!templ.IsEmpty());
12983 LocalContext context;
12984 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
12985 GenerateSomeGarbage();
12986 context->Global()->Set(v8_str("o"), fun->NewInstance());
12987 v8::TryCatch try_catch;
12990 "var receiver = {};"
12991 "receiver.__proto__ = o;"
12993 "var saved_result = 0;"
12994 "for (var i = 0; i < 100; i++) {"
12995 " result = receiver.method(41);"
12997 " saved_result = result;"
13001 CHECK(try_catch.HasCaught());
13002 // TODO(verwaest): Adjust message.
13003 CHECK_EQ(v8_str("TypeError: undefined is not a function"),
13004 try_catch.Exception()->ToString());
13005 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13009 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) {
13010 v8::Isolate* isolate = CcTest::isolate();
13011 v8::HandleScope scope(isolate);
13012 v8::Handle<v8::FunctionTemplate> fun_templ =
13013 v8::FunctionTemplate::New(isolate);
13014 v8::Handle<v8::FunctionTemplate> method_templ = v8::FunctionTemplate::New(
13015 isolate, FastApiCallback_SimpleSignature, v8_str("method_data"),
13016 v8::Signature::New(isolate, fun_templ));
13017 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
13018 proto_templ->Set(v8_str("method"), method_templ);
13019 fun_templ->SetHiddenPrototype(true);
13020 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
13021 CHECK(!templ.IsEmpty());
13022 LocalContext context;
13023 v8::Handle<v8::Function> fun = fun_templ->GetFunction();
13024 GenerateSomeGarbage();
13025 context->Global()->Set(v8_str("o"), fun->NewInstance());
13026 v8::TryCatch try_catch;
13029 "var receiver = {};"
13030 "receiver.__proto__ = o;"
13032 "var saved_result = 0;"
13033 "for (var i = 0; i < 100; i++) {"
13034 " result = receiver.method(41);"
13036 " saved_result = result;"
13037 " receiver = Object.create(receiver);"
13040 CHECK(try_catch.HasCaught());
13041 CHECK_EQ(v8_str("TypeError: Illegal invocation"),
13042 try_catch.Exception()->ToString());
13043 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13047 v8::Handle<Value> keyed_call_ic_function;
13049 static void InterceptorKeyedCallICGetter(
13050 Local<String> name,
13051 const v8::PropertyCallbackInfo<v8::Value>& info) {
13052 ApiTestFuzzer::Fuzz();
13053 if (v8_str("x")->Equals(name)) {
13054 info.GetReturnValue().Set(keyed_call_ic_function);
13059 // Test the case when we stored cacheable lookup into
13060 // a stub, but the function name changed (to another cacheable function).
13061 THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
13062 v8::Isolate* isolate = CcTest::isolate();
13063 v8::HandleScope scope(isolate);
13064 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13065 templ->SetNamedPropertyHandler(NoBlockGetterX);
13066 LocalContext context;
13067 context->Global()->Set(v8_str("o"), templ->NewInstance());
13069 "proto = new Object();"
13070 "proto.y = function(x) { return x + 1; };"
13071 "proto.z = function(x) { return x - 1; };"
13072 "o.__proto__ = proto;"
13074 "var method = 'y';"
13075 "for (var i = 0; i < 10; i++) {"
13076 " if (i == 5) { method = 'z'; };"
13077 " result += o[method](41);"
13079 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13083 // Test the case when we stored cacheable lookup into
13084 // a stub, but the function name changed (and the new function is present
13085 // both before and after the interceptor in the prototype chain).
13086 THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
13087 v8::Isolate* isolate = CcTest::isolate();
13088 v8::HandleScope scope(isolate);
13089 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13090 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
13091 LocalContext context;
13092 context->Global()->Set(v8_str("proto1"), templ->NewInstance());
13093 keyed_call_ic_function =
13094 v8_compile("function f(x) { return x - 1; }; f")->Run();
13096 "o = new Object();"
13097 "proto2 = new Object();"
13098 "o.y = function(x) { return x + 1; };"
13099 "proto2.y = function(x) { return x + 2; };"
13100 "o.__proto__ = proto1;"
13101 "proto1.__proto__ = proto2;"
13103 "var method = 'x';"
13104 "for (var i = 0; i < 10; i++) {"
13105 " if (i == 5) { method = 'y'; };"
13106 " result += o[method](41);"
13108 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13112 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
13113 // on the global object.
13114 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
13115 v8::Isolate* isolate = CcTest::isolate();
13116 v8::HandleScope scope(isolate);
13117 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13118 templ->SetNamedPropertyHandler(NoBlockGetterX);
13119 LocalContext context;
13120 context->Global()->Set(v8_str("o"), templ->NewInstance());
13122 "function inc(x) { return x + 1; };"
13124 "function dec(x) { return x - 1; };"
13126 "o.__proto__ = this;"
13127 "this.__proto__.x = inc;"
13128 "this.__proto__.y = dec;"
13130 "var method = 'x';"
13131 "for (var i = 0; i < 10; i++) {"
13132 " if (i == 5) { method = 'y'; };"
13133 " result += o[method](41);"
13135 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13139 // Test the case when actual function to call sits on global object.
13140 THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
13141 v8::Isolate* isolate = CcTest::isolate();
13142 v8::HandleScope scope(isolate);
13143 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13144 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
13145 LocalContext context;
13146 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
13149 "function len(x) { return x.length; };"
13150 "o.__proto__ = this;"
13151 "var m = 'parseFloat';"
13153 "for (var i = 0; i < 10; i++) {"
13156 " saved_result = result;"
13158 " result = o[m]('239');"
13160 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
13161 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
13165 // Test the map transition before the interceptor.
13166 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
13167 v8::Isolate* isolate = CcTest::isolate();
13168 v8::HandleScope scope(isolate);
13169 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13170 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
13171 LocalContext context;
13172 context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
13175 "var o = new Object();"
13176 "o.__proto__ = proto;"
13177 "o.method = function(x) { return x + 1; };"
13178 "var m = 'method';"
13180 "for (var i = 0; i < 10; i++) {"
13181 " if (i == 5) { o.method = function(x) { return x - 1; }; };"
13182 " result += o[m](41);"
13184 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13188 // Test the map transition after the interceptor.
13189 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
13190 v8::Isolate* isolate = CcTest::isolate();
13191 v8::HandleScope scope(isolate);
13192 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
13193 templ_o->SetNamedPropertyHandler(NoBlockGetterX);
13194 LocalContext context;
13195 context->Global()->Set(v8_str("o"), templ_o->NewInstance());
13198 "var proto = new Object();"
13199 "o.__proto__ = proto;"
13200 "proto.method = function(x) { return x + 1; };"
13201 "var m = 'method';"
13203 "for (var i = 0; i < 10; i++) {"
13204 " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
13205 " result += o[m](41);"
13207 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
13211 static int interceptor_call_count = 0;
13213 static void InterceptorICRefErrorGetter(
13214 Local<String> name,
13215 const v8::PropertyCallbackInfo<v8::Value>& info) {
13216 ApiTestFuzzer::Fuzz();
13217 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
13218 info.GetReturnValue().Set(call_ic_function2);
13223 // This test should hit load and call ICs for the interceptor case.
13224 // Once in a while, the interceptor will reply that a property was not
13225 // found in which case we should get a reference error.
13226 THREADED_TEST(InterceptorICReferenceErrors) {
13227 v8::Isolate* isolate = CcTest::isolate();
13228 v8::HandleScope scope(isolate);
13229 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13230 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
13231 LocalContext context(0, templ, v8::Handle<Value>());
13232 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
13233 v8::Handle<Value> value = CompileRun(
13235 " for (var i = 0; i < 1000; i++) {"
13236 " try { x; } catch(e) { return true; }"
13241 CHECK_EQ(true, value->BooleanValue());
13242 interceptor_call_count = 0;
13243 value = CompileRun(
13245 " for (var i = 0; i < 1000; i++) {"
13246 " try { x(42); } catch(e) { return true; }"
13251 CHECK_EQ(true, value->BooleanValue());
13255 static int interceptor_ic_exception_get_count = 0;
13257 static void InterceptorICExceptionGetter(
13258 Local<String> name,
13259 const v8::PropertyCallbackInfo<v8::Value>& info) {
13260 ApiTestFuzzer::Fuzz();
13261 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
13262 info.GetReturnValue().Set(call_ic_function3);
13264 if (interceptor_ic_exception_get_count == 20) {
13265 info.GetIsolate()->ThrowException(v8_num(42));
13271 // Test interceptor load/call IC where the interceptor throws an
13272 // exception once in a while.
13273 THREADED_TEST(InterceptorICGetterExceptions) {
13274 interceptor_ic_exception_get_count = 0;
13275 v8::Isolate* isolate = CcTest::isolate();
13276 v8::HandleScope scope(isolate);
13277 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13278 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
13279 LocalContext context(0, templ, v8::Handle<Value>());
13280 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
13281 v8::Handle<Value> value = CompileRun(
13283 " for (var i = 0; i < 100; i++) {"
13284 " try { x; } catch(e) { return true; }"
13289 CHECK_EQ(true, value->BooleanValue());
13290 interceptor_ic_exception_get_count = 0;
13291 value = CompileRun(
13293 " for (var i = 0; i < 100; i++) {"
13294 " try { x(42); } catch(e) { return true; }"
13299 CHECK_EQ(true, value->BooleanValue());
13303 static int interceptor_ic_exception_set_count = 0;
13305 static void InterceptorICExceptionSetter(
13307 Local<Value> value,
13308 const v8::PropertyCallbackInfo<v8::Value>& info) {
13309 ApiTestFuzzer::Fuzz();
13310 if (++interceptor_ic_exception_set_count > 20) {
13311 info.GetIsolate()->ThrowException(v8_num(42));
13316 // Test interceptor store IC where the interceptor throws an exception
13317 // once in a while.
13318 THREADED_TEST(InterceptorICSetterExceptions) {
13319 interceptor_ic_exception_set_count = 0;
13320 v8::Isolate* isolate = CcTest::isolate();
13321 v8::HandleScope scope(isolate);
13322 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13323 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
13324 LocalContext context(0, templ, v8::Handle<Value>());
13325 v8::Handle<Value> value = CompileRun(
13327 " for (var i = 0; i < 100; i++) {"
13328 " try { x = 42; } catch(e) { return true; }"
13333 CHECK_EQ(true, value->BooleanValue());
13337 // Test that we ignore null interceptors.
13338 THREADED_TEST(NullNamedInterceptor) {
13339 v8::Isolate* isolate = CcTest::isolate();
13340 v8::HandleScope scope(isolate);
13341 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13342 templ->SetNamedPropertyHandler(
13343 static_cast<v8::NamedPropertyGetterCallback>(0));
13344 LocalContext context;
13345 templ->Set(CcTest::isolate(), "x", v8_num(42));
13346 v8::Handle<v8::Object> obj = templ->NewInstance();
13347 context->Global()->Set(v8_str("obj"), obj);
13348 v8::Handle<Value> value = CompileRun("obj.x");
13349 CHECK(value->IsInt32());
13350 CHECK_EQ(42, value->Int32Value());
13354 // Test that we ignore null interceptors.
13355 THREADED_TEST(NullIndexedInterceptor) {
13356 v8::Isolate* isolate = CcTest::isolate();
13357 v8::HandleScope scope(isolate);
13358 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
13359 templ->SetIndexedPropertyHandler(
13360 static_cast<v8::IndexedPropertyGetterCallback>(0));
13361 LocalContext context;
13362 templ->Set(CcTest::isolate(), "42", v8_num(42));
13363 v8::Handle<v8::Object> obj = templ->NewInstance();
13364 context->Global()->Set(v8_str("obj"), obj);
13365 v8::Handle<Value> value = CompileRun("obj[42]");
13366 CHECK(value->IsInt32());
13367 CHECK_EQ(42, value->Int32Value());
13371 THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
13372 v8::Isolate* isolate = CcTest::isolate();
13373 v8::HandleScope scope(isolate);
13374 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13375 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
13377 env->Global()->Set(v8_str("obj"),
13378 templ->GetFunction()->NewInstance());
13379 ExpectTrue("obj.x === 42");
13380 ExpectTrue("!obj.propertyIsEnumerable('x')");
13384 static void ThrowingGetter(Local<String> name,
13385 const v8::PropertyCallbackInfo<v8::Value>& info) {
13386 ApiTestFuzzer::Fuzz();
13387 info.GetIsolate()->ThrowException(Handle<Value>());
13388 info.GetReturnValue().SetUndefined();
13392 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) {
13393 LocalContext context;
13394 HandleScope scope(context->GetIsolate());
13396 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
13397 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate();
13398 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter);
13400 Local<Object> instance = templ->GetFunction()->NewInstance();
13402 Local<Object> another = Object::New(context->GetIsolate());
13403 another->SetPrototype(instance);
13405 Local<Object> with_js_getter = CompileRun(
13407 "o.__defineGetter__('f', function() { throw undefined; });\n"
13408 "o\n").As<Object>();
13409 CHECK(!with_js_getter.IsEmpty());
13411 TryCatch try_catch;
13413 Local<Value> result = instance->GetRealNamedProperty(v8_str("f"));
13414 CHECK(try_catch.HasCaught());
13416 CHECK(result.IsEmpty());
13418 result = another->GetRealNamedProperty(v8_str("f"));
13419 CHECK(try_catch.HasCaught());
13421 CHECK(result.IsEmpty());
13423 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f"));
13424 CHECK(try_catch.HasCaught());
13426 CHECK(result.IsEmpty());
13428 result = another->Get(v8_str("f"));
13429 CHECK(try_catch.HasCaught());
13431 CHECK(result.IsEmpty());
13433 result = with_js_getter->GetRealNamedProperty(v8_str("f"));
13434 CHECK(try_catch.HasCaught());
13436 CHECK(result.IsEmpty());
13438 result = with_js_getter->Get(v8_str("f"));
13439 CHECK(try_catch.HasCaught());
13441 CHECK(result.IsEmpty());
13445 static void ThrowingCallbackWithTryCatch(
13446 const v8::FunctionCallbackInfo<v8::Value>& args) {
13447 TryCatch try_catch;
13448 // Verboseness is important: it triggers message delivery which can call into
13450 try_catch.SetVerbose(true);
13451 CompileRun("throw 'from JS';");
13452 CHECK(try_catch.HasCaught());
13453 CHECK(!CcTest::i_isolate()->has_pending_exception());
13454 CHECK(!CcTest::i_isolate()->has_scheduled_exception());
13458 static int call_depth;
13461 static void WithTryCatch(Handle<Message> message, Handle<Value> data) {
13462 TryCatch try_catch;
13466 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) {
13467 if (--call_depth) CompileRun("throw 'ThrowInJS';");
13471 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) {
13472 if (--call_depth) CcTest::isolate()->ThrowException(v8_str("ThrowViaApi"));
13476 static void WebKitLike(Handle<Message> message, Handle<Value> data) {
13477 Handle<String> errorMessageString = message->Get();
13478 CHECK(!errorMessageString.IsEmpty());
13479 message->GetStackTrace();
13480 message->GetScriptOrigin().ResourceName();
13484 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) {
13485 LocalContext context;
13486 v8::Isolate* isolate = context->GetIsolate();
13487 HandleScope scope(isolate);
13489 Local<Function> func =
13490 FunctionTemplate::New(isolate,
13491 ThrowingCallbackWithTryCatch)->GetFunction();
13492 context->Global()->Set(v8_str("func"), func);
13494 MessageCallback callbacks[] =
13495 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch };
13496 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) {
13497 MessageCallback callback = callbacks[i];
13498 if (callback != NULL) {
13499 V8::AddMessageListener(callback);
13501 // Some small number to control number of times message handler should
13502 // throw an exception.
13505 "var thrown = false;\n"
13506 "try { func(); } catch(e) { thrown = true; }\n"
13508 if (callback != NULL) {
13509 V8::RemoveMessageListeners(callback);
13515 static void ParentGetter(Local<String> name,
13516 const v8::PropertyCallbackInfo<v8::Value>& info) {
13517 ApiTestFuzzer::Fuzz();
13518 info.GetReturnValue().Set(v8_num(1));
13522 static void ChildGetter(Local<String> name,
13523 const v8::PropertyCallbackInfo<v8::Value>& info) {
13524 ApiTestFuzzer::Fuzz();
13525 info.GetReturnValue().Set(v8_num(42));
13529 THREADED_TEST(Overriding) {
13530 LocalContext context;
13531 v8::Isolate* isolate = context->GetIsolate();
13532 v8::HandleScope scope(isolate);
13534 // Parent template.
13535 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(isolate);
13536 Local<ObjectTemplate> parent_instance_templ =
13537 parent_templ->InstanceTemplate();
13538 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter);
13540 // Template that inherits from the parent template.
13541 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(isolate);
13542 Local<ObjectTemplate> child_instance_templ =
13543 child_templ->InstanceTemplate();
13544 child_templ->Inherit(parent_templ);
13545 // Override 'f'. The child version of 'f' should get called for child
13547 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter);
13548 // Add 'g' twice. The 'g' added last should get called for instances.
13549 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter);
13550 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter);
13552 // Add 'h' as an accessor to the proto template with ReadOnly attributes
13553 // so 'h' can be shadowed on the instance object.
13554 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate();
13555 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0,
13556 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13558 // Add 'i' as an accessor to the instance template with ReadOnly attributes
13559 // but the attribute does not have effect because it is duplicated with
13561 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0,
13562 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly);
13566 // Instantiate the child template.
13567 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance();
13569 // Check that the child function overrides the parent one.
13570 context->Global()->Set(v8_str("o"), instance);
13571 Local<Value> value = v8_compile("o.f")->Run();
13572 // Check that the 'g' that was added last is hit.
13573 CHECK_EQ(42, value->Int32Value());
13574 value = v8_compile("o.g")->Run();
13575 CHECK_EQ(42, value->Int32Value());
13577 // Check that 'h' cannot be shadowed.
13578 value = v8_compile("o.h = 3; o.h")->Run();
13579 CHECK_EQ(1, value->Int32Value());
13581 // Check that 'i' cannot be shadowed or changed.
13582 value = v8_compile("o.i = 3; o.i")->Run();
13583 CHECK_EQ(42, value->Int32Value());
13587 static void IsConstructHandler(
13588 const v8::FunctionCallbackInfo<v8::Value>& args) {
13589 ApiTestFuzzer::Fuzz();
13590 args.GetReturnValue().Set(args.IsConstructCall());
13594 THREADED_TEST(IsConstructCall) {
13595 v8::Isolate* isolate = CcTest::isolate();
13596 v8::HandleScope scope(isolate);
13598 // Function template with call handler.
13599 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13600 templ->SetCallHandler(IsConstructHandler);
13602 LocalContext context;
13604 context->Global()->Set(v8_str("f"), templ->GetFunction());
13605 Local<Value> value = v8_compile("f()")->Run();
13606 CHECK(!value->BooleanValue());
13607 value = v8_compile("new f()")->Run();
13608 CHECK(value->BooleanValue());
13612 THREADED_TEST(ObjectProtoToString) {
13613 v8::Isolate* isolate = CcTest::isolate();
13614 v8::HandleScope scope(isolate);
13615 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13616 templ->SetClassName(v8_str("MyClass"));
13618 LocalContext context;
13620 Local<String> customized_tostring = v8_str("customized toString");
13622 // Replace Object.prototype.toString
13623 v8_compile("Object.prototype.toString = function() {"
13624 " return 'customized toString';"
13627 // Normal ToString call should call replaced Object.prototype.toString
13628 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13629 Local<String> value = instance->ToString();
13630 CHECK(value->IsString() && value->Equals(customized_tostring));
13632 // ObjectProtoToString should not call replace toString function.
13633 value = instance->ObjectProtoToString();
13634 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13637 value = context->Global()->ObjectProtoToString();
13638 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13640 // Check ordinary object
13641 Local<Value> object = v8_compile("new Object()")->Run();
13642 value = object.As<v8::Object>()->ObjectProtoToString();
13643 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13647 TEST(ObjectProtoToStringES6) {
13648 // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
13649 i::FLAG_harmony_tostring = true;
13650 LocalContext context;
13651 v8::Isolate* isolate = CcTest::isolate();
13652 v8::HandleScope scope(isolate);
13653 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
13654 templ->SetClassName(v8_str("MyClass"));
13656 Local<String> customized_tostring = v8_str("customized toString");
13658 // Replace Object.prototype.toString
13660 "Object.prototype.toString = function() {"
13661 " return 'customized toString';"
13664 // Normal ToString call should call replaced Object.prototype.toString
13665 Local<v8::Object> instance = templ->GetFunction()->NewInstance();
13666 Local<String> value = instance->ToString();
13667 CHECK(value->IsString() && value->Equals(customized_tostring));
13669 // ObjectProtoToString should not call replace toString function.
13670 value = instance->ObjectProtoToString();
13671 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
13674 value = context->Global()->ObjectProtoToString();
13675 CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
13677 // Check ordinary object
13678 Local<Value> object = CompileRun("new Object()");
13679 value = object.As<v8::Object>()->ObjectProtoToString();
13680 CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
13682 // Check that ES6 semantics using @@toStringTag work
13683 Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
13685 #define TEST_TOSTRINGTAG(type, tag, expected) \
13687 object = CompileRun("new " #type "()"); \
13688 object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
13689 value = object.As<v8::Object>()->ObjectProtoToString(); \
13690 CHECK(value->IsString() && \
13691 value->Equals(v8_str("[object " #expected "]"))); \
13694 TEST_TOSTRINGTAG(Array, Object, Object);
13695 TEST_TOSTRINGTAG(Object, Arguments, ~Arguments);
13696 TEST_TOSTRINGTAG(Object, Array, ~Array);
13697 TEST_TOSTRINGTAG(Object, Boolean, ~Boolean);
13698 TEST_TOSTRINGTAG(Object, Date, ~Date);
13699 TEST_TOSTRINGTAG(Object, Error, ~Error);
13700 TEST_TOSTRINGTAG(Object, Function, ~Function);
13701 TEST_TOSTRINGTAG(Object, Number, ~Number);
13702 TEST_TOSTRINGTAG(Object, RegExp, ~RegExp);
13703 TEST_TOSTRINGTAG(Object, String, ~String);
13704 TEST_TOSTRINGTAG(Object, Foo, Foo);
13706 #undef TEST_TOSTRINGTAG
13708 // @@toStringTag getter throws
13709 Local<Value> obj = v8::Object::New(isolate);
13710 obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
13712 TryCatch try_catch;
13713 value = obj.As<v8::Object>()->ObjectProtoToString();
13714 CHECK(value.IsEmpty());
13715 CHECK(try_catch.HasCaught());
13718 // @@toStringTag getter does not throw
13719 obj = v8::Object::New(isolate);
13720 obj.As<v8::Object>()->SetAccessor(
13721 toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
13723 TryCatch try_catch;
13724 value = obj.As<v8::Object>()->ObjectProtoToString();
13725 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
13726 CHECK(!try_catch.HasCaught());
13729 // JS @@toStringTag value
13730 obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
13732 TryCatch try_catch;
13733 value = obj.As<v8::Object>()->ObjectProtoToString();
13734 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
13735 CHECK(!try_catch.HasCaught());
13738 // JS @@toStringTag getter throws
13740 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13741 " get: function() { throw 'Test'; }"
13744 TryCatch try_catch;
13745 value = obj.As<v8::Object>()->ObjectProtoToString();
13746 CHECK(value.IsEmpty());
13747 CHECK(try_catch.HasCaught());
13750 // JS @@toStringTag getter does not throw
13752 "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
13753 " get: function() { return 'Test'; }"
13756 TryCatch try_catch;
13757 value = obj.As<v8::Object>()->ObjectProtoToString();
13758 CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
13759 CHECK(!try_catch.HasCaught());
13764 THREADED_TEST(ObjectGetConstructorName) {
13765 LocalContext context;
13766 v8::HandleScope scope(context->GetIsolate());
13767 v8_compile("function Parent() {};"
13768 "function Child() {};"
13769 "Child.prototype = new Parent();"
13770 "var outer = { inner: function() { } };"
13771 "var p = new Parent();"
13772 "var c = new Child();"
13773 "var x = new outer.inner();")->Run();
13775 Local<v8::Value> p = context->Global()->Get(v8_str("p"));
13776 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
13777 v8_str("Parent")));
13779 Local<v8::Value> c = context->Global()->Get(v8_str("c"));
13780 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
13783 Local<v8::Value> x = context->Global()->Get(v8_str("x"));
13784 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
13785 v8_str("outer.inner")));
13789 bool ApiTestFuzzer::fuzzing_ = false;
13790 v8::base::Semaphore ApiTestFuzzer::all_tests_done_(0);
13791 int ApiTestFuzzer::active_tests_;
13792 int ApiTestFuzzer::tests_being_run_;
13793 int ApiTestFuzzer::current_;
13796 // We are in a callback and want to switch to another thread (if we
13797 // are currently running the thread fuzzing test).
13798 void ApiTestFuzzer::Fuzz() {
13799 if (!fuzzing_) return;
13800 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_;
13801 test->ContextSwitch();
13805 // Let the next thread go. Since it is also waiting on the V8 lock it may
13806 // not start immediately.
13807 bool ApiTestFuzzer::NextThread() {
13808 int test_position = GetNextTestNumber();
13809 const char* test_name = RegisterThreadedTest::nth(current_)->name();
13810 if (test_position == current_) {
13812 printf("Stay with %s\n", test_name);
13815 if (kLogThreading) {
13816 printf("Switch from %s to %s\n",
13818 RegisterThreadedTest::nth(test_position)->name());
13820 current_ = test_position;
13821 RegisterThreadedTest::nth(current_)->fuzzer_->gate_.Signal();
13826 void ApiTestFuzzer::Run() {
13827 // When it is our turn...
13830 // ... get the V8 lock and start running the test.
13831 v8::Locker locker(CcTest::isolate());
13834 // This test finished.
13837 // If it was the last then signal that fact.
13838 if (active_tests_ == 0) {
13839 all_tests_done_.Signal();
13841 // Otherwise select a new test and start that.
13847 static unsigned linear_congruential_generator;
13850 void ApiTestFuzzer::SetUp(PartOfTest part) {
13851 linear_congruential_generator = i::FLAG_testing_prng_seed;
13853 int count = RegisterThreadedTest::count();
13854 int start = count * part / (LAST_PART + 1);
13855 int end = (count * (part + 1) / (LAST_PART + 1)) - 1;
13856 active_tests_ = tests_being_run_ = end - start + 1;
13857 for (int i = 0; i < tests_being_run_; i++) {
13858 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start);
13860 for (int i = 0; i < active_tests_; i++) {
13861 RegisterThreadedTest::nth(i)->fuzzer_->Start();
13866 static void CallTestNumber(int test_number) {
13867 (RegisterThreadedTest::nth(test_number)->callback())();
13871 void ApiTestFuzzer::RunAllTests() {
13872 // Set off the first test.
13875 // Wait till they are all done.
13876 all_tests_done_.Wait();
13880 int ApiTestFuzzer::GetNextTestNumber() {
13883 next_test = (linear_congruential_generator >> 16) % tests_being_run_;
13884 linear_congruential_generator *= 1664525u;
13885 linear_congruential_generator += 1013904223u;
13886 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_);
13891 void ApiTestFuzzer::ContextSwitch() {
13892 // If the new thread is the same as the current thread there is nothing to do.
13893 if (NextThread()) {
13894 // Now it can start.
13895 v8::Unlocker unlocker(CcTest::isolate());
13896 // Wait till someone starts us again.
13903 void ApiTestFuzzer::TearDown() {
13905 for (int i = 0; i < RegisterThreadedTest::count(); i++) {
13906 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
13907 if (fuzzer != NULL) fuzzer->Join();
13912 // Lets not be needlessly self-referential.
13914 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART);
13915 ApiTestFuzzer::RunAllTests();
13916 ApiTestFuzzer::TearDown();
13921 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART);
13922 ApiTestFuzzer::RunAllTests();
13923 ApiTestFuzzer::TearDown();
13928 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART);
13929 ApiTestFuzzer::RunAllTests();
13930 ApiTestFuzzer::TearDown();
13935 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART);
13936 ApiTestFuzzer::RunAllTests();
13937 ApiTestFuzzer::TearDown();
13941 void ApiTestFuzzer::CallTest() {
13942 v8::Isolate::Scope scope(CcTest::isolate());
13944 printf("Start test %d\n", test_number_);
13945 CallTestNumber(test_number_);
13947 printf("End test %d\n", test_number_);
13951 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) {
13952 v8::Isolate* isolate = args.GetIsolate();
13953 CHECK(v8::Locker::IsLocked(isolate));
13954 ApiTestFuzzer::Fuzz();
13955 v8::Unlocker unlocker(isolate);
13956 const char* code = "throw 7;";
13958 v8::Locker nested_locker(isolate);
13959 v8::HandleScope scope(isolate);
13960 v8::Handle<Value> exception;
13961 { v8::TryCatch try_catch;
13962 v8::Handle<Value> value = CompileRun(code);
13963 CHECK(value.IsEmpty());
13964 CHECK(try_catch.HasCaught());
13965 // Make sure to wrap the exception in a new handle because
13966 // the handle returned from the TryCatch is destroyed
13967 // when the TryCatch is destroyed.
13968 exception = Local<Value>::New(isolate, try_catch.Exception());
13970 args.GetIsolate()->ThrowException(exception);
13975 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) {
13976 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
13977 ApiTestFuzzer::Fuzz();
13978 v8::Unlocker unlocker(CcTest::isolate());
13979 const char* code = "throw 7;";
13981 v8::Locker nested_locker(CcTest::isolate());
13982 v8::HandleScope scope(args.GetIsolate());
13983 v8::Handle<Value> value = CompileRun(code);
13984 CHECK(value.IsEmpty());
13985 args.GetReturnValue().Set(v8_str("foo"));
13990 // These are locking tests that don't need to be run again
13991 // as part of the locking aggregation tests.
13992 TEST(NestedLockers) {
13993 v8::Isolate* isolate = CcTest::isolate();
13994 v8::Locker locker(isolate);
13995 CHECK(v8::Locker::IsLocked(isolate));
13997 v8::HandleScope scope(env->GetIsolate());
13998 Local<v8::FunctionTemplate> fun_templ =
13999 v8::FunctionTemplate::New(isolate, ThrowInJS);
14000 Local<Function> fun = fun_templ->GetFunction();
14001 env->Global()->Set(v8_str("throw_in_js"), fun);
14002 Local<Script> script = v8_compile("(function () {"
14010 CHECK_EQ(91, script->Run()->Int32Value());
14014 // These are locking tests that don't need to be run again
14015 // as part of the locking aggregation tests.
14016 TEST(NestedLockersNoTryCatch) {
14017 v8::Locker locker(CcTest::isolate());
14019 v8::HandleScope scope(env->GetIsolate());
14020 Local<v8::FunctionTemplate> fun_templ =
14021 v8::FunctionTemplate::New(env->GetIsolate(), ThrowInJSNoCatch);
14022 Local<Function> fun = fun_templ->GetFunction();
14023 env->Global()->Set(v8_str("throw_in_js"), fun);
14024 Local<Script> script = v8_compile("(function () {"
14032 CHECK_EQ(91, script->Run()->Int32Value());
14036 THREADED_TEST(RecursiveLocking) {
14037 v8::Locker locker(CcTest::isolate());
14039 v8::Locker locker2(CcTest::isolate());
14040 CHECK(v8::Locker::IsLocked(CcTest::isolate()));
14045 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) {
14046 ApiTestFuzzer::Fuzz();
14047 v8::Unlocker unlocker(CcTest::isolate());
14051 THREADED_TEST(LockUnlockLock) {
14053 v8::Locker locker(CcTest::isolate());
14054 v8::HandleScope scope(CcTest::isolate());
14056 Local<v8::FunctionTemplate> fun_templ =
14057 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
14058 Local<Function> fun = fun_templ->GetFunction();
14059 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
14060 Local<Script> script = v8_compile("(function () {"
14061 " unlock_for_a_moment();"
14064 CHECK_EQ(42, script->Run()->Int32Value());
14067 v8::Locker locker(CcTest::isolate());
14068 v8::HandleScope scope(CcTest::isolate());
14070 Local<v8::FunctionTemplate> fun_templ =
14071 v8::FunctionTemplate::New(CcTest::isolate(), UnlockForAMoment);
14072 Local<Function> fun = fun_templ->GetFunction();
14073 env->Global()->Set(v8_str("unlock_for_a_moment"), fun);
14074 Local<Script> script = v8_compile("(function () {"
14075 " unlock_for_a_moment();"
14078 CHECK_EQ(42, script->Run()->Int32Value());
14083 static int GetGlobalObjectsCount() {
14085 i::HeapIterator it(CcTest::heap());
14086 for (i::HeapObject* object = it.next(); object != NULL; object = it.next())
14087 if (object->IsJSGlobalObject()) count++;
14092 static void CheckSurvivingGlobalObjectsCount(int expected) {
14093 // We need to collect all garbage twice to be sure that everything
14094 // has been collected. This is because inline caches are cleared in
14095 // the first garbage collection but some of the maps have already
14096 // been marked at that point. Therefore some of the maps are not
14097 // collected until the second garbage collection.
14098 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14099 CcTest::heap()->CollectAllGarbage(i::Heap::kMakeHeapIterableMask);
14100 int count = GetGlobalObjectsCount();
14102 if (count != expected) CcTest::heap()->TracePathToGlobal();
14104 CHECK_EQ(expected, count);
14108 TEST(DontLeakGlobalObjects) {
14109 // Regression test for issues 1139850 and 1174891.
14111 i::FLAG_expose_gc = true;
14112 v8::V8::Initialize();
14114 for (int i = 0; i < 5; i++) {
14115 { v8::HandleScope scope(CcTest::isolate());
14116 LocalContext context;
14118 CcTest::isolate()->ContextDisposedNotification();
14119 CheckSurvivingGlobalObjectsCount(0);
14121 { v8::HandleScope scope(CcTest::isolate());
14122 LocalContext context;
14123 v8_compile("Date")->Run();
14125 CcTest::isolate()->ContextDisposedNotification();
14126 CheckSurvivingGlobalObjectsCount(0);
14128 { v8::HandleScope scope(CcTest::isolate());
14129 LocalContext context;
14130 v8_compile("/aaa/")->Run();
14132 CcTest::isolate()->ContextDisposedNotification();
14133 CheckSurvivingGlobalObjectsCount(0);
14135 { v8::HandleScope scope(CcTest::isolate());
14136 const char* extension_list[] = { "v8/gc" };
14137 v8::ExtensionConfiguration extensions(1, extension_list);
14138 LocalContext context(&extensions);
14139 v8_compile("gc();")->Run();
14141 CcTest::isolate()->ContextDisposedNotification();
14142 CheckSurvivingGlobalObjectsCount(0);
14147 TEST(CopyablePersistent) {
14148 LocalContext context;
14149 v8::Isolate* isolate = context->GetIsolate();
14150 i::GlobalHandles* globals =
14151 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14152 int initial_handles = globals->global_handles_count();
14153 typedef v8::Persistent<v8::Object, v8::CopyablePersistentTraits<v8::Object> >
14156 CopyableObject handle1;
14158 v8::HandleScope scope(isolate);
14159 handle1.Reset(isolate, v8::Object::New(isolate));
14161 CHECK_EQ(initial_handles + 1, globals->global_handles_count());
14162 CopyableObject handle2;
14164 CHECK(handle1 == handle2);
14165 CHECK_EQ(initial_handles + 2, globals->global_handles_count());
14166 CopyableObject handle3(handle2);
14167 CHECK(handle1 == handle3);
14168 CHECK_EQ(initial_handles + 3, globals->global_handles_count());
14170 // Verify autodispose
14171 CHECK_EQ(initial_handles, globals->global_handles_count());
14175 static void WeakApiCallback(
14176 const v8::WeakCallbackData<v8::Object, Persistent<v8::Object> >& data) {
14177 Local<Value> value = data.GetValue()->Get(v8_str("key"));
14178 CHECK_EQ(231, static_cast<int32_t>(Local<v8::Integer>::Cast(value)->Value()));
14179 data.GetParameter()->Reset();
14180 delete data.GetParameter();
14184 TEST(WeakCallbackApi) {
14185 LocalContext context;
14186 v8::Isolate* isolate = context->GetIsolate();
14187 i::GlobalHandles* globals =
14188 reinterpret_cast<i::Isolate*>(isolate)->global_handles();
14189 int initial_handles = globals->global_handles_count();
14191 v8::HandleScope scope(isolate);
14192 v8::Local<v8::Object> obj = v8::Object::New(isolate);
14193 obj->Set(v8_str("key"), v8::Integer::New(isolate, 231));
14194 v8::Persistent<v8::Object>* handle =
14195 new v8::Persistent<v8::Object>(isolate, obj);
14196 handle->SetWeak<v8::Object, v8::Persistent<v8::Object> >(handle,
14199 reinterpret_cast<i::Isolate*>(isolate)->heap()->
14200 CollectAllGarbage(i::Heap::kNoGCFlags);
14201 // Verify disposed.
14202 CHECK_EQ(initial_handles, globals->global_handles_count());
14206 v8::Persistent<v8::Object> some_object;
14207 v8::Persistent<v8::Object> bad_handle;
14209 void NewPersistentHandleCallback(
14210 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14211 v8::HandleScope scope(data.GetIsolate());
14212 bad_handle.Reset(data.GetIsolate(), some_object);
14213 data.GetParameter()->Reset();
14217 THREADED_TEST(NewPersistentHandleFromWeakCallback) {
14218 LocalContext context;
14219 v8::Isolate* isolate = context->GetIsolate();
14221 v8::Persistent<v8::Object> handle1, handle2;
14223 v8::HandleScope scope(isolate);
14224 some_object.Reset(isolate, v8::Object::New(isolate));
14225 handle1.Reset(isolate, v8::Object::New(isolate));
14226 handle2.Reset(isolate, v8::Object::New(isolate));
14228 // Note: order is implementation dependent alas: currently
14229 // global handle nodes are processed by PostGarbageCollectionProcessing
14230 // in reverse allocation order, so if second allocated handle is deleted,
14231 // weak callback of the first handle would be able to 'reallocate' it.
14232 handle1.SetWeak(&handle1, NewPersistentHandleCallback);
14234 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14238 v8::Persistent<v8::Object> to_be_disposed;
14240 void DisposeAndForceGcCallback(
14241 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14242 to_be_disposed.Reset();
14243 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
14244 data.GetParameter()->Reset();
14248 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) {
14249 LocalContext context;
14250 v8::Isolate* isolate = context->GetIsolate();
14252 v8::Persistent<v8::Object> handle1, handle2;
14254 v8::HandleScope scope(isolate);
14255 handle1.Reset(isolate, v8::Object::New(isolate));
14256 handle2.Reset(isolate, v8::Object::New(isolate));
14258 handle1.SetWeak(&handle1, DisposeAndForceGcCallback);
14259 to_be_disposed.Reset(isolate, handle2);
14260 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14263 void DisposingCallback(
14264 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14265 data.GetParameter()->Reset();
14268 void HandleCreatingCallback(
14269 const v8::WeakCallbackData<v8::Object, v8::Persistent<v8::Object> >& data) {
14270 v8::HandleScope scope(data.GetIsolate());
14271 v8::Persistent<v8::Object>(data.GetIsolate(),
14272 v8::Object::New(data.GetIsolate()));
14273 data.GetParameter()->Reset();
14277 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) {
14278 LocalContext context;
14279 v8::Isolate* isolate = context->GetIsolate();
14281 v8::Persistent<v8::Object> handle1, handle2, handle3;
14283 v8::HandleScope scope(isolate);
14284 handle3.Reset(isolate, v8::Object::New(isolate));
14285 handle2.Reset(isolate, v8::Object::New(isolate));
14286 handle1.Reset(isolate, v8::Object::New(isolate));
14288 handle2.SetWeak(&handle2, DisposingCallback);
14289 handle3.SetWeak(&handle3, HandleCreatingCallback);
14290 CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
14294 THREADED_TEST(CheckForCrossContextObjectLiterals) {
14295 v8::V8::Initialize();
14298 const char* sources[nof] = {
14299 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }",
14303 for (int i = 0; i < nof; i++) {
14304 const char* source = sources[i];
14305 { v8::HandleScope scope(CcTest::isolate());
14306 LocalContext context;
14307 CompileRun(source);
14309 { v8::HandleScope scope(CcTest::isolate());
14310 LocalContext context;
14311 CompileRun(source);
14317 static v8::Handle<Value> NestedScope(v8::Local<Context> env) {
14318 v8::EscapableHandleScope inner(env->GetIsolate());
14320 v8::Local<Value> three = v8_num(3);
14321 v8::Local<Value> value = inner.Escape(three);
14327 THREADED_TEST(NestedHandleScopeAndContexts) {
14328 v8::Isolate* isolate = CcTest::isolate();
14329 v8::HandleScope outer(isolate);
14330 v8::Local<Context> env = Context::New(isolate);
14332 v8::Handle<Value> value = NestedScope(env);
14333 v8::Handle<String> str(value->ToString());
14334 CHECK(!str.IsEmpty());
14339 static bool MatchPointers(void* key1, void* key2) {
14340 return key1 == key2;
14344 struct SymbolInfo {
14351 class SetFunctionEntryHookTest {
14353 SetFunctionEntryHookTest() {
14354 CHECK(instance_ == NULL);
14357 ~SetFunctionEntryHookTest() {
14358 CHECK(instance_ == this);
14363 symbol_locations_.clear();
14364 invocations_.clear();
14367 void OnJitEvent(const v8::JitCodeEvent* event);
14368 static void JitEvent(const v8::JitCodeEvent* event) {
14369 CHECK(instance_ != NULL);
14370 instance_->OnJitEvent(event);
14373 void OnEntryHook(uintptr_t function,
14374 uintptr_t return_addr_location);
14375 static void EntryHook(uintptr_t function,
14376 uintptr_t return_addr_location) {
14377 CHECK(instance_ != NULL);
14378 instance_->OnEntryHook(function, return_addr_location);
14381 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
14382 CHECK(instance_ != NULL);
14383 args.GetReturnValue().Set(v8_num(42));
14385 void RunLoopInNewEnv(v8::Isolate* isolate);
14387 // Records addr as location of symbol.
14388 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol);
14390 // Finds the symbol containing addr
14391 SymbolInfo* FindSymbolForAddr(i::Address addr);
14392 // Returns the number of invocations where the caller name contains
14393 // \p caller_name and the function name contains \p function_name.
14394 int CountInvocations(const char* caller_name,
14395 const char* function_name);
14397 i::Handle<i::JSFunction> foo_func_;
14398 i::Handle<i::JSFunction> bar_func_;
14400 typedef std::map<size_t, SymbolInfo> SymbolMap;
14401 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap;
14402 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap;
14403 SymbolMap symbols_;
14404 SymbolLocationMap symbol_locations_;
14405 InvocationMap invocations_;
14407 static SetFunctionEntryHookTest* instance_;
14409 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL;
14412 // Returns true if addr is in the range [start, start+len).
14413 static bool Overlaps(i::Address start, size_t len, i::Address addr) {
14414 if (start <= addr && start + len > addr)
14420 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr,
14421 SymbolInfo* symbol) {
14422 // Insert the symbol at the new location.
14423 SymbolLocationMap::iterator it =
14424 symbol_locations_.insert(std::make_pair(addr, symbol)).first;
14425 // Now erase symbols to the left and right that overlap this one.
14426 while (it != symbol_locations_.begin()) {
14427 SymbolLocationMap::iterator left = it;
14429 if (!Overlaps(left->first, left->second->size, addr))
14431 symbol_locations_.erase(left);
14434 // Now erase symbols to the left and right that overlap this one.
14436 SymbolLocationMap::iterator right = it;
14438 if (right == symbol_locations_.end())
14440 if (!Overlaps(addr, symbol->size, right->first))
14442 symbol_locations_.erase(right);
14447 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) {
14448 switch (event->type) {
14449 case v8::JitCodeEvent::CODE_ADDED: {
14450 CHECK(event->code_start != NULL);
14451 CHECK_NE(0, static_cast<int>(event->code_len));
14452 CHECK(event->name.str != NULL);
14453 size_t symbol_id = symbols_.size();
14455 // Record the new symbol.
14456 SymbolInfo& info = symbols_[symbol_id];
14457 info.id = symbol_id;
14458 info.size = event->code_len;
14459 info.name.assign(event->name.str, event->name.str + event->name.len);
14461 // And record it's location.
14462 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info);
14466 case v8::JitCodeEvent::CODE_MOVED: {
14467 // We would like to never see code move that we haven't seen before,
14468 // but the code creation event does not happen until the line endings
14469 // have been calculated (this is so that we can report the line in the
14470 // script at which the function source is found, see
14471 // Compiler::RecordFunctionCompilation) and the line endings
14472 // calculations can cause a GC, which can move the newly created code
14473 // before its existence can be logged.
14474 SymbolLocationMap::iterator it(
14475 symbol_locations_.find(
14476 reinterpret_cast<i::Address>(event->code_start)));
14477 if (it != symbol_locations_.end()) {
14478 // Found a symbol at this location, move it.
14479 SymbolInfo* info = it->second;
14480 symbol_locations_.erase(it);
14481 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start),
14490 void SetFunctionEntryHookTest::OnEntryHook(
14491 uintptr_t function, uintptr_t return_addr_location) {
14492 // Get the function's code object.
14493 i::Code* function_code = i::Code::GetCodeFromTargetAddress(
14494 reinterpret_cast<i::Address>(function));
14495 CHECK(function_code != NULL);
14497 // Then try and look up the caller's code object.
14498 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location);
14500 // Count the invocation.
14501 SymbolInfo* caller_symbol = FindSymbolForAddr(caller);
14502 SymbolInfo* function_symbol =
14503 FindSymbolForAddr(reinterpret_cast<i::Address>(function));
14504 ++invocations_[std::make_pair(caller_symbol, function_symbol)];
14506 if (!bar_func_.is_null() && function_code == bar_func_->code()) {
14507 // Check that we have a symbol for the "bar" function at the right location.
14508 SymbolLocationMap::iterator it(
14509 symbol_locations_.find(function_code->instruction_start()));
14510 CHECK(it != symbol_locations_.end());
14513 if (!foo_func_.is_null() && function_code == foo_func_->code()) {
14514 // Check that we have a symbol for "foo" at the right location.
14515 SymbolLocationMap::iterator it(
14516 symbol_locations_.find(function_code->instruction_start()));
14517 CHECK(it != symbol_locations_.end());
14522 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) {
14523 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr));
14524 // Do we have a direct hit on a symbol?
14525 if (it != symbol_locations_.end()) {
14526 if (it->first == addr)
14530 // If not a direct hit, it'll have to be the previous symbol.
14531 if (it == symbol_locations_.begin())
14535 size_t offs = addr - it->first;
14536 if (offs < it->second->size)
14543 int SetFunctionEntryHookTest::CountInvocations(
14544 const char* caller_name, const char* function_name) {
14545 InvocationMap::iterator it(invocations_.begin());
14546 int invocations = 0;
14547 for (; it != invocations_.end(); ++it) {
14548 SymbolInfo* caller = it->first.first;
14549 SymbolInfo* function = it->first.second;
14551 // Filter out non-matching functions.
14552 if (function_name != NULL) {
14553 if (function->name.find(function_name) == std::string::npos)
14557 // Filter out non-matching callers.
14558 if (caller_name != NULL) {
14559 if (caller == NULL)
14561 if (caller->name.find(caller_name) == std::string::npos)
14565 // It matches add the invocation count to the tally.
14566 invocations += it->second;
14569 return invocations;
14573 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) {
14574 v8::HandleScope outer(isolate);
14575 v8::Local<Context> env = Context::New(isolate);
14578 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
14579 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(isolate, RuntimeCallback));
14580 env->Global()->Set(v8_str("obj"), t->NewInstance());
14582 const char* script =
14583 "function bar() {\n"
14585 " for (i = 0; i < 100; ++i)\n"
14589 "function foo(i) { return i * i; }\n"
14590 "// Invoke on the runtime function.\n"
14592 CompileRun(script);
14593 bar_func_ = i::Handle<i::JSFunction>::cast(
14594 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
14595 DCHECK(!bar_func_.is_null());
14598 i::Handle<i::JSFunction>::cast(
14599 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
14600 DCHECK(!foo_func_.is_null());
14602 v8::Handle<v8::Value> value = CompileRun("bar();");
14603 CHECK(value->IsNumber());
14604 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14606 // Test the optimized codegen path.
14607 value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
14609 CHECK(value->IsNumber());
14610 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
14616 void SetFunctionEntryHookTest::RunTest() {
14617 // Work in a new isolate throughout.
14618 v8::Isolate::CreateParams create_params;
14619 create_params.entry_hook = EntryHook;
14620 create_params.code_event_handler = JitEvent;
14621 v8::Isolate* isolate = v8::Isolate::New(create_params);
14624 v8::Isolate::Scope scope(isolate);
14626 RunLoopInNewEnv(isolate);
14628 // Check the exepected invocation counts.
14629 CHECK_EQ(2, CountInvocations(NULL, "bar"));
14630 CHECK_EQ(200, CountInvocations("bar", "foo"));
14631 CHECK_EQ(200, CountInvocations(NULL, "foo"));
14633 // Verify that we have an entry hook on some specific stubs.
14634 CHECK_NE(0, CountInvocations(NULL, "CEntryStub"));
14635 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub"));
14636 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline"));
14638 isolate->Dispose();
14642 // Make sure a second isolate is unaffected by the previous entry hook.
14643 isolate = v8::Isolate::New();
14645 v8::Isolate::Scope scope(isolate);
14647 // Reset the entry count to zero and set the entry hook.
14648 RunLoopInNewEnv(isolate);
14650 // We should record no invocations in this isolate.
14651 CHECK_EQ(0, static_cast<int>(invocations_.size()));
14654 isolate->Dispose();
14658 TEST(SetFunctionEntryHook) {
14659 // FunctionEntryHook does not work well with experimental natives.
14660 // Experimental natives are compiled during snapshot deserialization.
14661 // This test breaks because InstallGetter (function from snapshot that
14662 // only gets called from experimental natives) is compiled with entry hooks.
14663 i::FLAG_allow_natives_syntax = true;
14664 i::FLAG_use_inlining = false;
14666 SetFunctionEntryHookTest test;
14671 static i::HashMap* code_map = NULL;
14672 static i::HashMap* jitcode_line_info = NULL;
14673 static int saw_bar = 0;
14674 static int move_events = 0;
14677 static bool FunctionNameIs(const char* expected,
14678 const v8::JitCodeEvent* event) {
14679 // Log lines for functions are of the general form:
14680 // "LazyCompile:<type><function_name>", where the type is one of
14682 static const char kPreamble[] = "LazyCompile:";
14683 static size_t kPreambleLen = sizeof(kPreamble) - 1;
14685 if (event->name.len < sizeof(kPreamble) - 1 ||
14686 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) {
14690 const char* tail = event->name.str + kPreambleLen;
14691 size_t tail_len = event->name.len - kPreambleLen;
14692 size_t expected_len = strlen(expected);
14693 if (tail_len > 1 && (*tail == '*' || *tail == '~')) {
14698 // Check for tails like 'bar :1'.
14699 if (tail_len > expected_len + 2 &&
14700 tail[expected_len] == ' ' &&
14701 tail[expected_len + 1] == ':' &&
14702 tail[expected_len + 2] &&
14703 !strncmp(tail, expected, expected_len)) {
14707 if (tail_len != expected_len)
14710 return strncmp(tail, expected, expected_len) == 0;
14714 static void event_handler(const v8::JitCodeEvent* event) {
14715 CHECK(event != NULL);
14716 CHECK(code_map != NULL);
14717 CHECK(jitcode_line_info != NULL);
14719 class DummyJitCodeLineInfo {
14722 switch (event->type) {
14723 case v8::JitCodeEvent::CODE_ADDED: {
14724 CHECK(event->code_start != NULL);
14725 CHECK_NE(0, static_cast<int>(event->code_len));
14726 CHECK(event->name.str != NULL);
14727 i::HashMap::Entry* entry =
14728 code_map->Lookup(event->code_start,
14729 i::ComputePointerHash(event->code_start),
14731 entry->value = reinterpret_cast<void*>(event->code_len);
14733 if (FunctionNameIs("bar", event)) {
14739 case v8::JitCodeEvent::CODE_MOVED: {
14740 uint32_t hash = i::ComputePointerHash(event->code_start);
14741 // We would like to never see code move that we haven't seen before,
14742 // but the code creation event does not happen until the line endings
14743 // have been calculated (this is so that we can report the line in the
14744 // script at which the function source is found, see
14745 // Compiler::RecordFunctionCompilation) and the line endings
14746 // calculations can cause a GC, which can move the newly created code
14747 // before its existence can be logged.
14748 i::HashMap::Entry* entry =
14749 code_map->Lookup(event->code_start, hash, false);
14750 if (entry != NULL) {
14753 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value);
14754 code_map->Remove(event->code_start, hash);
14756 entry = code_map->Lookup(event->new_code_start,
14757 i::ComputePointerHash(event->new_code_start),
14759 CHECK(entry != NULL);
14760 entry->value = reinterpret_cast<void*>(event->code_len);
14765 case v8::JitCodeEvent::CODE_REMOVED:
14766 // Object/code removal events are currently not dispatched from the GC.
14770 // For CODE_START_LINE_INFO_RECORDING event, we will create one
14771 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We
14772 // record it in jitcode_line_info.
14773 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
14774 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo();
14775 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
14776 temp_event->user_data = line_info;
14777 i::HashMap::Entry* entry =
14778 jitcode_line_info->Lookup(line_info,
14779 i::ComputePointerHash(line_info),
14781 entry->value = reinterpret_cast<void*>(line_info);
14784 // For these two events, we will check whether the event->user_data
14785 // data structure is created before during CODE_START_LINE_INFO_RECORDING
14786 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling.
14787 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
14788 CHECK(event->user_data != NULL);
14789 uint32_t hash = i::ComputePointerHash(event->user_data);
14790 i::HashMap::Entry* entry =
14791 jitcode_line_info->Lookup(event->user_data, hash, false);
14792 CHECK(entry != NULL);
14793 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data);
14797 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
14798 CHECK(event->user_data != NULL);
14799 uint32_t hash = i::ComputePointerHash(event->user_data);
14800 i::HashMap::Entry* entry =
14801 jitcode_line_info->Lookup(event->user_data, hash, false);
14802 CHECK(entry != NULL);
14807 // Impossible event.
14814 UNINITIALIZED_TEST(SetJitCodeEventHandler) {
14815 i::FLAG_stress_compaction = true;
14816 i::FLAG_incremental_marking = false;
14817 if (i::FLAG_never_compact) return;
14818 const char* script =
14821 " for (i = 0; i < 100; ++i)"
14825 "function foo(i) { return i * i; };"
14828 // Run this test in a new isolate to make sure we don't
14829 // have remnants of state from other code.
14830 v8::Isolate* isolate = v8::Isolate::New();
14832 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
14833 i::Heap* heap = i_isolate->heap();
14836 v8::HandleScope scope(isolate);
14837 i::HashMap code(MatchPointers);
14840 i::HashMap lineinfo(MatchPointers);
14841 jitcode_line_info = &lineinfo;
14846 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler);
14848 // Generate new code objects sparsely distributed across several
14849 // different fragmented code-space pages.
14850 const int kIterations = 10;
14851 for (int i = 0; i < kIterations; ++i) {
14852 LocalContext env(isolate);
14853 i::AlwaysAllocateScope always_allocate(i_isolate);
14854 SimulateFullSpace(heap->code_space());
14855 CompileRun(script);
14857 // Keep a strong reference to the code object in the handle scope.
14858 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast(
14859 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code());
14860 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast(
14861 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code());
14863 // Clear the compilation cache to get more wastage.
14864 reinterpret_cast<i::Isolate*>(isolate)->compilation_cache()->Clear();
14867 // Force code movement.
14868 heap->CollectAllAvailableGarbage("TestSetJitCodeEventHandler");
14870 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14872 CHECK_LE(kIterations, saw_bar);
14873 CHECK_LT(0, move_events);
14876 jitcode_line_info = NULL;
14880 isolate->Dispose();
14882 // Do this in a new isolate.
14883 isolate = v8::Isolate::New();
14886 // Verify that we get callbacks for existing code objects when we
14887 // request enumeration of existing code.
14889 v8::HandleScope scope(isolate);
14890 LocalContext env(isolate);
14891 CompileRun(script);
14893 // Now get code through initial iteration.
14894 i::HashMap code(MatchPointers);
14897 i::HashMap lineinfo(MatchPointers);
14898 jitcode_line_info = &lineinfo;
14900 isolate->SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting,
14902 isolate->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
14904 jitcode_line_info = NULL;
14905 // We expect that we got some events. Note that if we could get code removal
14906 // notifications, we could compare two collections, one created by listening
14907 // from the time of creation of an isolate, and the other by subscribing
14908 // with EnumExisting.
14909 CHECK_LT(0, code.occupancy());
14915 isolate->Dispose();
14919 THREADED_TEST(ExternalAllocatedMemory) {
14920 v8::Isolate* isolate = CcTest::isolate();
14921 v8::HandleScope outer(isolate);
14922 v8::Local<Context> env(Context::New(isolate));
14923 CHECK(!env.IsEmpty());
14924 const int64_t kSize = 1024*1024;
14925 int64_t baseline = isolate->AdjustAmountOfExternalAllocatedMemory(0);
14926 CHECK_EQ(baseline + kSize,
14927 isolate->AdjustAmountOfExternalAllocatedMemory(kSize));
14929 isolate->AdjustAmountOfExternalAllocatedMemory(-kSize));
14933 // Regression test for issue 54, object templates with internal fields
14934 // but no accessors or interceptors did not get their internal field
14935 // count set on instances.
14936 THREADED_TEST(Regress54) {
14937 LocalContext context;
14938 v8::Isolate* isolate = context->GetIsolate();
14939 v8::HandleScope outer(isolate);
14940 static v8::Persistent<v8::ObjectTemplate> templ;
14941 if (templ.IsEmpty()) {
14942 v8::EscapableHandleScope inner(isolate);
14943 v8::Local<v8::ObjectTemplate> local = v8::ObjectTemplate::New(isolate);
14944 local->SetInternalFieldCount(1);
14945 templ.Reset(isolate, inner.Escape(local));
14947 v8::Handle<v8::Object> result =
14948 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance();
14949 CHECK_EQ(1, result->InternalFieldCount());
14953 // If part of the threaded tests, this test makes ThreadingTest fail
14955 TEST(CatchStackOverflow) {
14956 LocalContext context;
14957 v8::HandleScope scope(context->GetIsolate());
14958 v8::TryCatch try_catch;
14959 v8::Handle<v8::Value> result = CompileRun(
14965 CHECK(result.IsEmpty());
14969 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script,
14970 const char* resource_name,
14972 v8::HandleScope scope(CcTest::isolate());
14973 v8::TryCatch try_catch;
14974 v8::Handle<v8::Value> result = script->Run();
14975 CHECK(result.IsEmpty());
14976 CHECK(try_catch.HasCaught());
14977 v8::Handle<v8::Message> message = try_catch.Message();
14978 CHECK(!message.IsEmpty());
14979 CHECK_EQ(10 + line_offset, message->GetLineNumber());
14980 CHECK_EQ(91, message->GetStartPosition());
14981 CHECK_EQ(92, message->GetEndPosition());
14982 CHECK_EQ(2, message->GetStartColumn());
14983 CHECK_EQ(3, message->GetEndColumn());
14984 v8::String::Utf8Value line(message->GetSourceLine());
14985 CHECK_EQ(" throw 'nirk';", *line);
14986 v8::String::Utf8Value name(message->GetScriptOrigin().ResourceName());
14987 CHECK_EQ(resource_name, *name);
14991 THREADED_TEST(TryCatchSourceInfo) {
14992 LocalContext context;
14993 v8::HandleScope scope(context->GetIsolate());
14994 v8::Local<v8::String> source = v8_str(
14995 "function Foo() {\n"
14999 "function Bar() {\n"
15003 "function Baz() {\n"
15009 const char* resource_name;
15010 v8::Handle<v8::Script> script;
15011 resource_name = "test.js";
15012 script = CompileWithOrigin(source, resource_name);
15013 CheckTryCatchSourceInfo(script, resource_name, 0);
15015 resource_name = "test1.js";
15016 v8::ScriptOrigin origin1(
15017 v8::String::NewFromUtf8(context->GetIsolate(), resource_name));
15018 script = v8::Script::Compile(source, &origin1);
15019 CheckTryCatchSourceInfo(script, resource_name, 0);
15021 resource_name = "test2.js";
15022 v8::ScriptOrigin origin2(
15023 v8::String::NewFromUtf8(context->GetIsolate(), resource_name),
15024 v8::Integer::New(context->GetIsolate(), 7));
15025 script = v8::Script::Compile(source, &origin2);
15026 CheckTryCatchSourceInfo(script, resource_name, 7);
15030 THREADED_TEST(CompilationCache) {
15031 LocalContext context;
15032 v8::HandleScope scope(context->GetIsolate());
15033 v8::Handle<v8::String> source0 =
15034 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
15035 v8::Handle<v8::String> source1 =
15036 v8::String::NewFromUtf8(context->GetIsolate(), "1234");
15037 v8::Handle<v8::Script> script0 = CompileWithOrigin(source0, "test.js");
15038 v8::Handle<v8::Script> script1 = CompileWithOrigin(source1, "test.js");
15039 v8::Handle<v8::Script> script2 =
15040 v8::Script::Compile(source0); // different origin
15041 CHECK_EQ(1234, script0->Run()->Int32Value());
15042 CHECK_EQ(1234, script1->Run()->Int32Value());
15043 CHECK_EQ(1234, script2->Run()->Int32Value());
15047 static void FunctionNameCallback(
15048 const v8::FunctionCallbackInfo<v8::Value>& args) {
15049 ApiTestFuzzer::Fuzz();
15050 args.GetReturnValue().Set(v8_num(42));
15054 THREADED_TEST(CallbackFunctionName) {
15055 LocalContext context;
15056 v8::Isolate* isolate = context->GetIsolate();
15057 v8::HandleScope scope(isolate);
15058 Local<ObjectTemplate> t = ObjectTemplate::New(isolate);
15059 t->Set(v8_str("asdf"),
15060 v8::FunctionTemplate::New(isolate, FunctionNameCallback));
15061 context->Global()->Set(v8_str("obj"), t->NewInstance());
15062 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name");
15063 CHECK(value->IsString());
15064 v8::String::Utf8Value name(value);
15065 CHECK_EQ("asdf", *name);
15069 THREADED_TEST(DateAccess) {
15070 LocalContext context;
15071 v8::HandleScope scope(context->GetIsolate());
15072 v8::Handle<v8::Value> date =
15073 v8::Date::New(context->GetIsolate(), 1224744689038.0);
15074 CHECK(date->IsDate());
15075 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf());
15079 void CheckProperties(v8::Isolate* isolate,
15080 v8::Handle<v8::Value> val,
15082 const char* elmv[]) {
15083 v8::Handle<v8::Object> obj = val.As<v8::Object>();
15084 v8::Handle<v8::Array> props = obj->GetPropertyNames();
15085 CHECK_EQ(elmc, props->Length());
15086 for (int i = 0; i < elmc; i++) {
15087 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
15088 CHECK_EQ(elmv[i], *elm);
15093 void CheckOwnProperties(v8::Isolate* isolate,
15094 v8::Handle<v8::Value> val,
15096 const char* elmv[]) {
15097 v8::Handle<v8::Object> obj = val.As<v8::Object>();
15098 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames();
15099 CHECK_EQ(elmc, props->Length());
15100 for (int i = 0; i < elmc; i++) {
15101 v8::String::Utf8Value elm(props->Get(v8::Integer::New(isolate, i)));
15102 CHECK_EQ(elmv[i], *elm);
15107 THREADED_TEST(PropertyEnumeration) {
15108 LocalContext context;
15109 v8::Isolate* isolate = context->GetIsolate();
15110 v8::HandleScope scope(isolate);
15111 v8::Handle<v8::Value> obj = CompileRun(
15114 "result[1] = {a: 1, b: 2};"
15115 "result[2] = [1, 2, 3];"
15116 "var proto = {x: 1, y: 2, z: 3};"
15117 "var x = { __proto__: proto, w: 0, z: 1 };"
15120 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
15121 CHECK_EQ(4, elms->Length());
15123 const char** elmv0 = NULL;
15125 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15126 CheckOwnProperties(
15127 isolate, elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15129 const char* elmv1[] = {"a", "b"};
15131 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
15132 CheckOwnProperties(
15133 isolate, elms->Get(v8::Integer::New(isolate, 1)), elmc1, elmv1);
15135 const char* elmv2[] = {"0", "1", "2"};
15137 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
15138 CheckOwnProperties(
15139 isolate, elms->Get(v8::Integer::New(isolate, 2)), elmc2, elmv2);
15141 const char* elmv3[] = {"w", "z", "x", "y"};
15143 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc3, elmv3);
15145 const char* elmv4[] = {"w", "z"};
15146 CheckOwnProperties(
15147 isolate, elms->Get(v8::Integer::New(isolate, 3)), elmc4, elmv4);
15151 THREADED_TEST(PropertyEnumeration2) {
15152 LocalContext context;
15153 v8::Isolate* isolate = context->GetIsolate();
15154 v8::HandleScope scope(isolate);
15155 v8::Handle<v8::Value> obj = CompileRun(
15158 "result[1] = {a: 1, b: 2};"
15159 "result[2] = [1, 2, 3];"
15160 "var proto = {x: 1, y: 2, z: 3};"
15161 "var x = { __proto__: proto, w: 0, z: 1 };"
15164 v8::Handle<v8::Array> elms = obj.As<v8::Array>();
15165 CHECK_EQ(4, elms->Length());
15167 const char** elmv0 = NULL;
15168 CheckProperties(isolate,
15169 elms->Get(v8::Integer::New(isolate, 0)), elmc0, elmv0);
15171 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(isolate, 0));
15172 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
15173 CHECK_EQ(0, props->Length());
15174 for (uint32_t i = 0; i < props->Length(); i++) {
15175 printf("p[%u]\n", i);
15179 static bool NamedSetAccessBlocker(Local<v8::Object> obj,
15181 v8::AccessType type,
15182 Local<Value> data) {
15183 return type != v8::ACCESS_SET;
15187 static bool IndexedSetAccessBlocker(Local<v8::Object> obj,
15189 v8::AccessType type,
15190 Local<Value> data) {
15191 return type != v8::ACCESS_SET;
15195 THREADED_TEST(DisableAccessChecksWhileConfiguring) {
15196 LocalContext context;
15197 v8::Isolate* isolate = context->GetIsolate();
15198 v8::HandleScope scope(isolate);
15199 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15200 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker,
15201 IndexedSetAccessBlocker);
15202 templ->Set(v8_str("x"), v8::True(isolate));
15203 Local<v8::Object> instance = templ->NewInstance();
15204 context->Global()->Set(v8_str("obj"), instance);
15205 Local<Value> value = CompileRun("obj.x");
15206 CHECK(value->BooleanValue());
15210 static bool NamedGetAccessBlocker(Local<v8::Object> obj,
15212 v8::AccessType type,
15213 Local<Value> data) {
15218 static bool IndexedGetAccessBlocker(Local<v8::Object> obj,
15220 v8::AccessType type,
15221 Local<Value> data) {
15227 THREADED_TEST(AccessChecksReenabledCorrectly) {
15228 LocalContext context;
15229 v8::Isolate* isolate = context->GetIsolate();
15230 v8::HandleScope scope(isolate);
15231 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
15232 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15233 IndexedGetAccessBlocker);
15234 templ->Set(v8_str("a"), v8_str("a"));
15235 // Add more than 8 (see kMaxFastProperties) properties
15236 // so that the constructor will force copying map.
15237 // Cannot sprintf, gcc complains unsafety.
15239 for (char i = '0'; i <= '9' ; i++) {
15241 for (char j = '0'; j <= '9'; j++) {
15243 for (char k = '0'; k <= '9'; k++) {
15246 templ->Set(v8_str(buf), v8::Number::New(isolate, k));
15251 Local<v8::Object> instance_1 = templ->NewInstance();
15252 context->Global()->Set(v8_str("obj_1"), instance_1);
15254 Local<Value> value_1 = CompileRun("obj_1.a");
15255 CHECK(value_1.IsEmpty());
15257 Local<v8::Object> instance_2 = templ->NewInstance();
15258 context->Global()->Set(v8_str("obj_2"), instance_2);
15260 Local<Value> value_2 = CompileRun("obj_2.a");
15261 CHECK(value_2.IsEmpty());
15265 // This tests that access check information remains on the global
15266 // object template when creating contexts.
15267 THREADED_TEST(AccessControlRepeatedContextCreation) {
15268 v8::Isolate* isolate = CcTest::isolate();
15269 v8::HandleScope handle_scope(isolate);
15270 v8::Handle<v8::ObjectTemplate> global_template =
15271 v8::ObjectTemplate::New(isolate);
15272 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker,
15273 IndexedSetAccessBlocker);
15274 i::Handle<i::ObjectTemplateInfo> internal_template =
15275 v8::Utils::OpenHandle(*global_template);
15276 CHECK(!internal_template->constructor()->IsUndefined());
15277 i::Handle<i::FunctionTemplateInfo> constructor(
15278 i::FunctionTemplateInfo::cast(internal_template->constructor()));
15279 CHECK(!constructor->access_check_info()->IsUndefined());
15280 v8::Local<Context> context0(Context::New(isolate, NULL, global_template));
15281 CHECK(!context0.IsEmpty());
15282 CHECK(!constructor->access_check_info()->IsUndefined());
15286 THREADED_TEST(TurnOnAccessCheck) {
15287 v8::Isolate* isolate = CcTest::isolate();
15288 v8::HandleScope handle_scope(isolate);
15290 // Create an environment with access check to the global object disabled by
15292 v8::Handle<v8::ObjectTemplate> global_template =
15293 v8::ObjectTemplate::New(isolate);
15294 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
15295 IndexedGetAccessBlocker,
15296 v8::Handle<v8::Value>(),
15298 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
15299 Context::Scope context_scope(context);
15301 // Set up a property and a number of functions.
15302 context->Global()->Set(v8_str("a"), v8_num(1));
15303 CompileRun("function f1() {return a;}"
15304 "function f2() {return a;}"
15305 "function g1() {return h();}"
15306 "function g2() {return h();}"
15307 "function h() {return 1;}");
15308 Local<Function> f1 =
15309 Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15310 Local<Function> f2 =
15311 Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15312 Local<Function> g1 =
15313 Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15314 Local<Function> g2 =
15315 Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15316 Local<Function> h =
15317 Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15319 // Get the global object.
15320 v8::Handle<v8::Object> global = context->Global();
15322 // Call f1 one time and f2 a number of times. This will ensure that f1 still
15323 // uses the runtime system to retreive property a whereas f2 uses global load
15325 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15326 for (int i = 0; i < 4; i++) {
15327 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15330 // Same for g1 and g2.
15331 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15332 for (int i = 0; i < 4; i++) {
15333 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15336 // Detach the global and turn on access check.
15337 Local<Object> hidden_global = Local<Object>::Cast(
15338 context->Global()->GetPrototype());
15339 context->DetachGlobal();
15340 hidden_global->TurnOnAccessCheck();
15342 // Failing access check results in exception.
15343 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15344 CHECK(f2->Call(global, 0, NULL).IsEmpty());
15345 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15346 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15348 // No failing access check when just returning a constant.
15349 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15353 static const char* kPropertyA = "a";
15354 static const char* kPropertyH = "h";
15356 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
15358 v8::AccessType type,
15359 Local<Value> data) {
15360 if (!name->IsString()) return false;
15361 i::Handle<i::String> name_handle =
15362 v8::Utils::OpenHandle(String::Cast(*name));
15363 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA))
15364 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH));
15368 THREADED_TEST(TurnOnAccessCheckAndRecompile) {
15369 v8::Isolate* isolate = CcTest::isolate();
15370 v8::HandleScope handle_scope(isolate);
15372 // Create an environment with access check to the global object disabled by
15373 // default. When the registered access checker will block access to properties
15375 v8::Handle<v8::ObjectTemplate> global_template =
15376 v8::ObjectTemplate::New(isolate);
15377 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
15378 IndexedGetAccessBlocker,
15379 v8::Handle<v8::Value>(),
15381 v8::Local<Context> context = Context::New(isolate, NULL, global_template);
15382 Context::Scope context_scope(context);
15384 // Set up a property and a number of functions.
15385 context->Global()->Set(v8_str("a"), v8_num(1));
15386 static const char* source = "function f1() {return a;}"
15387 "function f2() {return a;}"
15388 "function g1() {return h();}"
15389 "function g2() {return h();}"
15390 "function h() {return 1;}";
15392 CompileRun(source);
15393 Local<Function> f1;
15394 Local<Function> f2;
15395 Local<Function> g1;
15396 Local<Function> g2;
15398 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
15399 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
15400 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
15401 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
15402 h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
15404 // Get the global object.
15405 v8::Handle<v8::Object> global = context->Global();
15407 // Call f1 one time and f2 a number of times. This will ensure that f1 still
15408 // uses the runtime system to retreive property a whereas f2 uses global load
15410 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
15411 for (int i = 0; i < 4; i++) {
15412 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
15415 // Same for g1 and g2.
15416 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
15417 for (int i = 0; i < 4; i++) {
15418 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
15421 // Detach the global and turn on access check now blocking access to property
15422 // a and function h.
15423 Local<Object> hidden_global = Local<Object>::Cast(
15424 context->Global()->GetPrototype());
15425 context->DetachGlobal();
15426 hidden_global->TurnOnAccessCheck();
15428 // Failing access check results in exception.
15429 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15430 CHECK(f2->Call(global, 0, NULL).IsEmpty());
15431 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15432 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15434 // No failing access check when just returning a constant.
15435 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
15437 // Now compile the source again. And get the newly compiled functions, except
15438 // for h for which access is blocked.
15439 CompileRun(source);
15440 f1 = Local<Function>::Cast(hidden_global->Get(v8_str("f1")));
15441 f2 = Local<Function>::Cast(hidden_global->Get(v8_str("f2")));
15442 g1 = Local<Function>::Cast(hidden_global->Get(v8_str("g1")));
15443 g2 = Local<Function>::Cast(hidden_global->Get(v8_str("g2")));
15444 CHECK(hidden_global->Get(v8_str("h")).IsEmpty());
15446 // Failing access check results in exception.
15447 v8::Local<v8::Value> result = f1->Call(global, 0, NULL);
15448 CHECK(result.IsEmpty());
15449 CHECK(f1->Call(global, 0, NULL).IsEmpty());
15450 CHECK(f2->Call(global, 0, NULL).IsEmpty());
15451 CHECK(g1->Call(global, 0, NULL).IsEmpty());
15452 CHECK(g2->Call(global, 0, NULL).IsEmpty());
15456 // Tests that ScriptData can be serialized and deserialized.
15457 TEST(PreCompileSerialization) {
15458 v8::V8::Initialize();
15460 v8::Isolate* isolate = env->GetIsolate();
15461 HandleScope handle_scope(isolate);
15463 i::FLAG_min_preparse_length = 0;
15464 const char* script = "function foo(a) { return a+1; }";
15465 v8::ScriptCompiler::Source source(v8_str(script));
15466 v8::ScriptCompiler::Compile(isolate, &source,
15467 v8::ScriptCompiler::kProduceParserCache);
15469 const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
15470 i::byte* serialized_data = i::NewArray<i::byte>(cd->length);
15471 i::MemCopy(serialized_data, cd->data, cd->length);
15474 i::ScriptData* deserialized = new i::ScriptData(serialized_data, cd->length);
15476 // Verify that the original is the same as the deserialized.
15477 CHECK_EQ(cd->length, deserialized->length());
15478 CHECK_EQ(0, memcmp(cd->data, deserialized->data(), cd->length));
15480 delete deserialized;
15481 i::DeleteArray(serialized_data);
15485 // This tests that we do not allow dictionary load/call inline caches
15486 // to use functions that have not yet been compiled. The potential
15487 // problem of loading a function that has not yet been compiled can
15488 // arise because we share code between contexts via the compilation
15490 THREADED_TEST(DictionaryICLoadedFunction) {
15491 v8::HandleScope scope(CcTest::isolate());
15493 for (int i = 0; i < 2; i++) {
15494 LocalContext context;
15495 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15496 context->Global()->Delete(v8_str("tmp"));
15497 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');");
15500 for (int i = 0; i < 2; i++) {
15501 LocalContext context;
15502 context->Global()->Set(v8_str("tmp"), v8::True(CcTest::isolate()));
15503 context->Global()->Delete(v8_str("tmp"));
15504 CompileRun("for (var j = 0; j < 10; j++) RegExp('')");
15509 // Test that cross-context new calls use the context of the callee to
15510 // create the new JavaScript object.
15511 THREADED_TEST(CrossContextNew) {
15512 v8::Isolate* isolate = CcTest::isolate();
15513 v8::HandleScope scope(isolate);
15514 v8::Local<Context> context0 = Context::New(isolate);
15515 v8::Local<Context> context1 = Context::New(isolate);
15517 // Allow cross-domain access.
15518 Local<String> token = v8_str("<security token>");
15519 context0->SetSecurityToken(token);
15520 context1->SetSecurityToken(token);
15522 // Set an 'x' property on the Object prototype and define a
15523 // constructor function in context0.
15525 CompileRun("Object.prototype.x = 42; function C() {};");
15528 // Call the constructor function from context0 and check that the
15529 // result has the 'x' property.
15531 context1->Global()->Set(v8_str("other"), context0->Global());
15532 Local<Value> value = CompileRun("var instance = new other.C(); instance.x");
15533 CHECK(value->IsInt32());
15534 CHECK_EQ(42, value->Int32Value());
15539 // Verify that we can clone an object
15540 TEST(ObjectClone) {
15542 v8::Isolate* isolate = env->GetIsolate();
15543 v8::HandleScope scope(isolate);
15545 const char* sample =
15547 "rv.alpha = 'hello';" \
15551 // Create an object, verify basics.
15552 Local<Value> val = CompileRun(sample);
15553 CHECK(val->IsObject());
15554 Local<v8::Object> obj = val.As<v8::Object>();
15555 obj->Set(v8_str("gamma"), v8_str("cloneme"));
15557 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha")));
15558 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15559 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma")));
15562 Local<v8::Object> clone = obj->Clone();
15563 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha")));
15564 CHECK_EQ(v8::Integer::New(isolate, 123), clone->Get(v8_str("beta")));
15565 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma")));
15567 // Set a property on the clone, verify each object.
15568 clone->Set(v8_str("beta"), v8::Integer::New(isolate, 456));
15569 CHECK_EQ(v8::Integer::New(isolate, 123), obj->Get(v8_str("beta")));
15570 CHECK_EQ(v8::Integer::New(isolate, 456), clone->Get(v8_str("beta")));
15574 class OneByteVectorResource : public v8::String::ExternalOneByteStringResource {
15576 explicit OneByteVectorResource(i::Vector<const char> vector)
15578 virtual ~OneByteVectorResource() {}
15579 virtual size_t length() const { return data_.length(); }
15580 virtual const char* data() const { return data_.start(); }
15582 i::Vector<const char> data_;
15586 class UC16VectorResource : public v8::String::ExternalStringResource {
15588 explicit UC16VectorResource(i::Vector<const i::uc16> vector)
15590 virtual ~UC16VectorResource() {}
15591 virtual size_t length() const { return data_.length(); }
15592 virtual const i::uc16* data() const { return data_.start(); }
15594 i::Vector<const i::uc16> data_;
15598 static void MorphAString(i::String* string,
15599 OneByteVectorResource* one_byte_resource,
15600 UC16VectorResource* uc16_resource) {
15601 CHECK(i::StringShape(string).IsExternal());
15602 if (string->IsOneByteRepresentation()) {
15603 // Check old map is not internalized or long.
15604 CHECK(string->map() == CcTest::heap()->external_one_byte_string_map());
15605 // Morph external string to be TwoByte string.
15606 string->set_map(CcTest::heap()->external_string_map());
15607 i::ExternalTwoByteString* morphed =
15608 i::ExternalTwoByteString::cast(string);
15609 morphed->set_resource(uc16_resource);
15611 // Check old map is not internalized or long.
15612 CHECK(string->map() == CcTest::heap()->external_string_map());
15613 // Morph external string to be one-byte string.
15614 string->set_map(CcTest::heap()->external_one_byte_string_map());
15615 i::ExternalOneByteString* morphed = i::ExternalOneByteString::cast(string);
15616 morphed->set_resource(one_byte_resource);
15621 // Test that we can still flatten a string if the components it is built up
15622 // from have been turned into 16 bit strings in the mean time.
15623 THREADED_TEST(MorphCompositeStringTest) {
15624 char utf_buffer[129];
15625 const char* c_string = "Now is the time for all good men"
15626 " to come to the aid of the party";
15627 uint16_t* two_byte_string = AsciiToTwoByteString(c_string);
15630 i::Factory* factory = CcTest::i_isolate()->factory();
15631 v8::HandleScope scope(env->GetIsolate());
15632 OneByteVectorResource one_byte_resource(
15633 i::Vector<const char>(c_string, i::StrLength(c_string)));
15634 UC16VectorResource uc16_resource(
15635 i::Vector<const uint16_t>(two_byte_string,
15636 i::StrLength(c_string)));
15639 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15640 &one_byte_resource).ToHandleChecked()));
15642 v8::Utils::ToLocal(factory->NewExternalStringFromOneByte(
15643 &one_byte_resource).ToHandleChecked()));
15645 env->Global()->Set(v8_str("lhs"), lhs);
15646 env->Global()->Set(v8_str("rhs"), rhs);
15649 "var cons = lhs + rhs;"
15650 "var slice = lhs.substring(1, lhs.length - 1);"
15651 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);");
15653 CHECK(lhs->IsOneByte());
15654 CHECK(rhs->IsOneByte());
15656 MorphAString(*v8::Utils::OpenHandle(*lhs), &one_byte_resource,
15658 MorphAString(*v8::Utils::OpenHandle(*rhs), &one_byte_resource,
15661 // This should UTF-8 without flattening, since everything is ASCII.
15662 Handle<String> cons = v8_compile("cons")->Run().As<String>();
15663 CHECK_EQ(128, cons->Utf8Length());
15665 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars));
15666 CHECK_EQ(128, nchars);
15667 CHECK_EQ(0, strcmp(
15669 "Now is the time for all good men to come to the aid of the party"
15670 "Now is the time for all good men to come to the aid of the party"));
15672 // Now do some stuff to make sure the strings are flattened, etc.
15674 "/[^a-z]/.test(cons);"
15675 "/[^a-z]/.test(slice);"
15676 "/[^a-z]/.test(slice_on_cons);");
15677 const char* expected_cons =
15678 "Now is the time for all good men to come to the aid of the party"
15679 "Now is the time for all good men to come to the aid of the party";
15680 const char* expected_slice =
15681 "ow is the time for all good men to come to the aid of the part";
15682 const char* expected_slice_on_cons =
15683 "ow is the time for all good men to come to the aid of the party"
15684 "Now is the time for all good men to come to the aid of the part";
15685 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_cons),
15686 env->Global()->Get(v8_str("cons")));
15687 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice),
15688 env->Global()->Get(v8_str("slice")));
15689 CHECK_EQ(String::NewFromUtf8(env->GetIsolate(), expected_slice_on_cons),
15690 env->Global()->Get(v8_str("slice_on_cons")));
15692 i::DeleteArray(two_byte_string);
15696 TEST(CompileExternalTwoByteSource) {
15697 LocalContext context;
15698 v8::HandleScope scope(context->GetIsolate());
15700 // This is a very short list of sources, which currently is to check for a
15701 // regression caused by r2703.
15702 const char* one_byte_sources[] = {
15704 "-0.5", // This mainly testes PushBack in the Scanner.
15705 "--0.5", // This mainly testes PushBack in the Scanner.
15708 // Compile the sources as external two byte strings.
15709 for (int i = 0; one_byte_sources[i] != NULL; i++) {
15710 uint16_t* two_byte_string = AsciiToTwoByteString(one_byte_sources[i]);
15711 TestResource* uc16_resource = new TestResource(two_byte_string);
15712 v8::Local<v8::String> source =
15713 v8::String::NewExternal(context->GetIsolate(), uc16_resource);
15714 v8::Script::Compile(source);
15719 #ifndef V8_INTERPRETED_REGEXP
15721 struct RegExpInterruptionData {
15722 v8::base::Atomic32 loop_count;
15723 UC16VectorResource* string_resource;
15724 v8::Persistent<v8::String> string;
15725 } regexp_interruption_data;
15728 class RegExpInterruptionThread : public v8::base::Thread {
15730 explicit RegExpInterruptionThread(v8::Isolate* isolate)
15731 : Thread(Options("TimeoutThread")), isolate_(isolate) {}
15733 virtual void Run() {
15734 for (v8::base::NoBarrier_Store(®exp_interruption_data.loop_count, 0);
15735 v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) < 7;
15736 v8::base::NoBarrier_AtomicIncrement(
15737 ®exp_interruption_data.loop_count, 1)) {
15738 v8::base::OS::Sleep(50); // Wait a bit before requesting GC.
15739 reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
15741 v8::base::OS::Sleep(50); // Wait a bit before terminating.
15742 v8::V8::TerminateExecution(isolate_);
15746 v8::Isolate* isolate_;
15750 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
15751 if (v8::base::NoBarrier_Load(®exp_interruption_data.loop_count) != 2) {
15754 v8::HandleScope scope(CcTest::isolate());
15755 v8::Local<v8::String> string = v8::Local<v8::String>::New(
15756 CcTest::isolate(), regexp_interruption_data.string);
15757 string->MakeExternal(regexp_interruption_data.string_resource);
15761 // Test that RegExp execution can be interrupted. Specifically, we test
15762 // * interrupting with GC
15763 // * turn the subject string from one-byte internal to two-byte external string
15764 // * force termination
15765 TEST(RegExpInterruption) {
15766 v8::HandleScope scope(CcTest::isolate());
15769 RegExpInterruptionThread timeout_thread(CcTest::isolate());
15771 v8::V8::AddGCPrologueCallback(RunBeforeGC);
15772 static const char* one_byte_content = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
15773 i::uc16* uc16_content = AsciiToTwoByteString(one_byte_content);
15774 v8::Local<v8::String> string = v8_str(one_byte_content);
15776 CcTest::global()->Set(v8_str("a"), string);
15777 regexp_interruption_data.string.Reset(CcTest::isolate(), string);
15778 regexp_interruption_data.string_resource = new UC16VectorResource(
15779 i::Vector<const i::uc16>(uc16_content, i::StrLength(one_byte_content)));
15781 v8::TryCatch try_catch;
15782 timeout_thread.Start();
15784 CompileRun("/((a*)*)*b/.exec(a)");
15785 CHECK(try_catch.HasTerminated());
15787 timeout_thread.Join();
15789 regexp_interruption_data.string.Reset();
15790 i::DeleteArray(uc16_content);
15793 #endif // V8_INTERPRETED_REGEXP
15796 // Test that we cannot set a property on the global object if there
15797 // is a read-only property in the prototype chain.
15798 TEST(ReadOnlyPropertyInGlobalProto) {
15799 v8::Isolate* isolate = CcTest::isolate();
15800 v8::HandleScope scope(isolate);
15801 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15802 LocalContext context(0, templ);
15803 v8::Handle<v8::Object> global = context->Global();
15804 v8::Handle<v8::Object> global_proto =
15805 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__")));
15806 global_proto->ForceSet(v8_str("x"), v8::Integer::New(isolate, 0),
15808 global_proto->ForceSet(v8_str("y"), v8::Integer::New(isolate, 0),
15810 // Check without 'eval' or 'with'.
15811 v8::Handle<v8::Value> res =
15812 CompileRun("function f() { x = 42; return x; }; f()");
15813 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15814 // Check with 'eval'.
15815 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()");
15816 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15817 // Check with 'with'.
15818 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()");
15819 CHECK_EQ(v8::Integer::New(isolate, 0), res);
15822 static int force_set_set_count = 0;
15823 static int force_set_get_count = 0;
15824 bool pass_on_get = false;
15826 static void ForceSetGetter(v8::Local<v8::String> name,
15827 const v8::PropertyCallbackInfo<v8::Value>& info) {
15828 force_set_get_count++;
15832 info.GetReturnValue().Set(3);
15835 static void ForceSetSetter(v8::Local<v8::String> name,
15836 v8::Local<v8::Value> value,
15837 const v8::PropertyCallbackInfo<void>& info) {
15838 force_set_set_count++;
15841 static void ForceSetInterceptSetter(
15842 v8::Local<v8::String> name,
15843 v8::Local<v8::Value> value,
15844 const v8::PropertyCallbackInfo<v8::Value>& info) {
15845 force_set_set_count++;
15846 info.GetReturnValue().SetUndefined();
15851 force_set_get_count = 0;
15852 force_set_set_count = 0;
15853 pass_on_get = false;
15855 v8::Isolate* isolate = CcTest::isolate();
15856 v8::HandleScope scope(isolate);
15857 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15858 v8::Handle<v8::String> access_property =
15859 v8::String::NewFromUtf8(isolate, "a");
15860 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter);
15861 LocalContext context(NULL, templ);
15862 v8::Handle<v8::Object> global = context->Global();
15864 // Ordinary properties
15865 v8::Handle<v8::String> simple_property =
15866 v8::String::NewFromUtf8(isolate, "p");
15867 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::ReadOnly);
15868 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15869 // This should fail because the property is read-only
15870 global->Set(simple_property, v8::Int32::New(isolate, 5));
15871 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15872 // This should succeed even though the property is read-only
15873 global->ForceSet(simple_property, v8::Int32::New(isolate, 6));
15874 CHECK_EQ(6, global->Get(simple_property)->Int32Value());
15877 CHECK_EQ(0, force_set_set_count);
15878 CHECK_EQ(0, force_set_get_count);
15879 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15880 // CHECK_EQ the property shouldn't override it, just call the setter
15881 // which in this case does nothing.
15882 global->Set(access_property, v8::Int32::New(isolate, 7));
15883 CHECK_EQ(3, global->Get(access_property)->Int32Value());
15884 CHECK_EQ(1, force_set_set_count);
15885 CHECK_EQ(2, force_set_get_count);
15886 // Forcing the property to be set should override the accessor without
15888 global->ForceSet(access_property, v8::Int32::New(isolate, 8));
15889 CHECK_EQ(8, global->Get(access_property)->Int32Value());
15890 CHECK_EQ(1, force_set_set_count);
15891 CHECK_EQ(2, force_set_get_count);
15895 TEST(ForceSetWithInterceptor) {
15896 force_set_get_count = 0;
15897 force_set_set_count = 0;
15898 pass_on_get = false;
15900 v8::Isolate* isolate = CcTest::isolate();
15901 v8::HandleScope scope(isolate);
15902 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15903 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
15904 LocalContext context(NULL, templ);
15905 v8::Handle<v8::Object> global = context->Global();
15907 v8::Handle<v8::String> some_property =
15908 v8::String::NewFromUtf8(isolate, "a");
15909 CHECK_EQ(0, force_set_set_count);
15910 CHECK_EQ(0, force_set_get_count);
15911 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15912 // Setting the property shouldn't override it, just call the setter
15913 // which in this case does nothing.
15914 global->Set(some_property, v8::Int32::New(isolate, 7));
15915 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15916 CHECK_EQ(1, force_set_set_count);
15917 CHECK_EQ(2, force_set_get_count);
15918 // Getting the property when the interceptor returns an empty handle
15919 // should yield undefined, since the property isn't present on the
15920 // object itself yet.
15921 pass_on_get = true;
15922 CHECK(global->Get(some_property)->IsUndefined());
15923 CHECK_EQ(1, force_set_set_count);
15924 CHECK_EQ(3, force_set_get_count);
15925 // Forcing the property to be set should cause the value to be
15926 // set locally without calling the interceptor.
15927 global->ForceSet(some_property, v8::Int32::New(isolate, 8));
15928 CHECK_EQ(8, global->Get(some_property)->Int32Value());
15929 CHECK_EQ(1, force_set_set_count);
15930 CHECK_EQ(4, force_set_get_count);
15931 // Reenabling the interceptor should cause it to take precedence over
15933 pass_on_get = false;
15934 CHECK_EQ(3, global->Get(some_property)->Int32Value());
15935 CHECK_EQ(1, force_set_set_count);
15936 CHECK_EQ(5, force_set_get_count);
15937 // The interceptor should also work for other properties
15938 CHECK_EQ(3, global->Get(v8::String::NewFromUtf8(isolate, "b"))
15940 CHECK_EQ(1, force_set_set_count);
15941 CHECK_EQ(6, force_set_get_count);
15945 THREADED_TEST(ForceDelete) {
15946 v8::Isolate* isolate = CcTest::isolate();
15947 v8::HandleScope scope(isolate);
15948 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15949 LocalContext context(NULL, templ);
15950 v8::Handle<v8::Object> global = context->Global();
15952 // Ordinary properties
15953 v8::Handle<v8::String> simple_property =
15954 v8::String::NewFromUtf8(isolate, "p");
15955 global->ForceSet(simple_property, v8::Int32::New(isolate, 4), v8::DontDelete);
15956 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15957 // This should fail because the property is dont-delete.
15958 CHECK(!global->Delete(simple_property));
15959 CHECK_EQ(4, global->Get(simple_property)->Int32Value());
15960 // This should succeed even though the property is dont-delete.
15961 CHECK(global->ForceDelete(simple_property));
15962 CHECK(global->Get(simple_property)->IsUndefined());
15966 static int force_delete_interceptor_count = 0;
15967 static bool pass_on_delete = false;
15970 static void ForceDeleteDeleter(
15971 v8::Local<v8::String> name,
15972 const v8::PropertyCallbackInfo<v8::Boolean>& info) {
15973 force_delete_interceptor_count++;
15974 if (pass_on_delete) return;
15975 info.GetReturnValue().Set(true);
15979 THREADED_TEST(ForceDeleteWithInterceptor) {
15980 force_delete_interceptor_count = 0;
15981 pass_on_delete = false;
15983 v8::Isolate* isolate = CcTest::isolate();
15984 v8::HandleScope scope(isolate);
15985 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
15986 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
15987 LocalContext context(NULL, templ);
15988 v8::Handle<v8::Object> global = context->Global();
15990 v8::Handle<v8::String> some_property =
15991 v8::String::NewFromUtf8(isolate, "a");
15992 global->ForceSet(some_property, v8::Integer::New(isolate, 42),
15995 // Deleting a property should get intercepted and nothing should
15997 CHECK_EQ(0, force_delete_interceptor_count);
15998 CHECK(global->Delete(some_property));
15999 CHECK_EQ(1, force_delete_interceptor_count);
16000 CHECK_EQ(42, global->Get(some_property)->Int32Value());
16001 // Deleting the property when the interceptor returns an empty
16002 // handle should not delete the property since it is DontDelete.
16003 pass_on_delete = true;
16004 CHECK(!global->Delete(some_property));
16005 CHECK_EQ(2, force_delete_interceptor_count);
16006 CHECK_EQ(42, global->Get(some_property)->Int32Value());
16007 // Forcing the property to be deleted should delete the value
16008 // without calling the interceptor.
16009 CHECK(global->ForceDelete(some_property));
16010 CHECK(global->Get(some_property)->IsUndefined());
16011 CHECK_EQ(2, force_delete_interceptor_count);
16015 // Make sure that forcing a delete invalidates any IC stubs, so we
16016 // don't read the hole value.
16017 THREADED_TEST(ForceDeleteIC) {
16018 LocalContext context;
16019 v8::HandleScope scope(context->GetIsolate());
16020 // Create a DontDelete variable on the global object.
16021 CompileRun("this.__proto__ = { foo: 'horse' };"
16022 "var foo = 'fish';"
16023 "function f() { return foo.length; }");
16024 // Initialize the IC for foo in f.
16025 CompileRun("for (var i = 0; i < 4; i++) f();");
16026 // Make sure the value of foo is correct before the deletion.
16027 CHECK_EQ(4, CompileRun("f()")->Int32Value());
16028 // Force the deletion of foo.
16029 CHECK(context->Global()->ForceDelete(v8_str("foo")));
16030 // Make sure the value for foo is read from the prototype, and that
16031 // we don't get in trouble with reading the deleted cell value
16033 CHECK_EQ(5, CompileRun("f()")->Int32Value());
16037 TEST(InlinedFunctionAcrossContexts) {
16038 i::FLAG_allow_natives_syntax = true;
16039 v8::Isolate* isolate = CcTest::isolate();
16040 v8::HandleScope outer_scope(isolate);
16041 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate);
16042 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate);
16046 v8::HandleScope inner_scope(CcTest::isolate());
16047 CompileRun("var G = 42; function foo() { return G; }");
16048 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo"));
16050 ctx2->Global()->Set(v8_str("o"), foo);
16051 v8::Local<v8::Value> res = CompileRun(
16052 "function f() { return o(); }"
16053 "for (var i = 0; i < 10; ++i) f();"
16054 "%OptimizeFunctionOnNextCall(f);"
16056 CHECK_EQ(42, res->Int32Value());
16058 v8::Handle<v8::String> G_property =
16059 v8::String::NewFromUtf8(CcTest::isolate(), "G");
16060 CHECK(ctx1->Global()->ForceDelete(G_property));
16067 " return e.toString();"
16070 "ReferenceError: G is not defined");
16077 static v8::Local<Context> calling_context0;
16078 static v8::Local<Context> calling_context1;
16079 static v8::Local<Context> calling_context2;
16082 // Check that the call to the callback is initiated in
16083 // calling_context2, the directly calling context is calling_context1
16084 // and the callback itself is in calling_context0.
16085 static void GetCallingContextCallback(
16086 const v8::FunctionCallbackInfo<v8::Value>& args) {
16087 ApiTestFuzzer::Fuzz();
16088 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0);
16089 CHECK(args.GetIsolate()->GetCallingContext() == calling_context1);
16090 CHECK(args.GetIsolate()->GetEnteredContext() == calling_context2);
16091 args.GetReturnValue().Set(42);
16095 THREADED_TEST(GetCurrentContextWhenNotInContext) {
16096 i::Isolate* isolate = CcTest::i_isolate();
16097 CHECK(isolate != NULL);
16098 CHECK(isolate->context() == NULL);
16099 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
16100 v8::HandleScope scope(v8_isolate);
16101 // The following should not crash, but return an empty handle.
16102 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext();
16103 CHECK(current.IsEmpty());
16107 THREADED_TEST(GetCallingContext) {
16108 v8::Isolate* isolate = CcTest::isolate();
16109 v8::HandleScope scope(isolate);
16111 Local<Context> calling_context0(Context::New(isolate));
16112 Local<Context> calling_context1(Context::New(isolate));
16113 Local<Context> calling_context2(Context::New(isolate));
16114 ::calling_context0 = calling_context0;
16115 ::calling_context1 = calling_context1;
16116 ::calling_context2 = calling_context2;
16118 // Allow cross-domain access.
16119 Local<String> token = v8_str("<security token>");
16120 calling_context0->SetSecurityToken(token);
16121 calling_context1->SetSecurityToken(token);
16122 calling_context2->SetSecurityToken(token);
16124 // Create an object with a C++ callback in context0.
16125 calling_context0->Enter();
16126 Local<v8::FunctionTemplate> callback_templ =
16127 v8::FunctionTemplate::New(isolate, GetCallingContextCallback);
16128 calling_context0->Global()->Set(v8_str("callback"),
16129 callback_templ->GetFunction());
16130 calling_context0->Exit();
16132 // Expose context0 in context1 and set up a function that calls the
16133 // callback function.
16134 calling_context1->Enter();
16135 calling_context1->Global()->Set(v8_str("context0"),
16136 calling_context0->Global());
16137 CompileRun("function f() { context0.callback() }");
16138 calling_context1->Exit();
16140 // Expose context1 in context2 and call the callback function in
16141 // context0 indirectly through f in context1.
16142 calling_context2->Enter();
16143 calling_context2->Global()->Set(v8_str("context1"),
16144 calling_context1->Global());
16145 CompileRun("context1.f()");
16146 calling_context2->Exit();
16147 ::calling_context0.Clear();
16148 ::calling_context1.Clear();
16149 ::calling_context2.Clear();
16153 // Check that a variable declaration with no explicit initialization
16154 // value does shadow an existing property in the prototype chain.
16155 THREADED_TEST(InitGlobalVarInProtoChain) {
16156 LocalContext context;
16157 v8::HandleScope scope(context->GetIsolate());
16158 // Introduce a variable in the prototype chain.
16159 CompileRun("__proto__.x = 42");
16160 v8::Handle<v8::Value> result = CompileRun("var x = 43; x");
16161 CHECK(!result->IsUndefined());
16162 CHECK_EQ(43, result->Int32Value());
16166 // Regression test for issue 398.
16167 // If a function is added to an object, creating a constant function
16168 // field, and the result is cloned, replacing the constant function on the
16169 // original should not affect the clone.
16170 // See http://code.google.com/p/v8/issues/detail?id=398
16171 THREADED_TEST(ReplaceConstantFunction) {
16172 LocalContext context;
16173 v8::Isolate* isolate = context->GetIsolate();
16174 v8::HandleScope scope(isolate);
16175 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
16176 v8::Handle<v8::FunctionTemplate> func_templ =
16177 v8::FunctionTemplate::New(isolate);
16178 v8::Handle<v8::String> foo_string =
16179 v8::String::NewFromUtf8(isolate, "foo");
16180 obj->Set(foo_string, func_templ->GetFunction());
16181 v8::Handle<v8::Object> obj_clone = obj->Clone();
16182 obj_clone->Set(foo_string,
16183 v8::String::NewFromUtf8(isolate, "Hello"));
16184 CHECK(!obj->Get(foo_string)->IsUndefined());
16188 static void CheckElementValue(i::Isolate* isolate,
16190 i::Handle<i::Object> obj,
16192 i::Object* element =
16193 *i::Object::GetElement(isolate, obj, offset).ToHandleChecked();
16194 CHECK_EQ(expected, i::Smi::cast(element)->value());
16198 THREADED_TEST(PixelArray) {
16199 LocalContext context;
16200 i::Isolate* isolate = CcTest::i_isolate();
16201 i::Factory* factory = isolate->factory();
16202 v8::HandleScope scope(context->GetIsolate());
16203 const int kElementCount = 260;
16204 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16205 i::Handle<i::ExternalUint8ClampedArray> pixels =
16206 i::Handle<i::ExternalUint8ClampedArray>::cast(
16207 factory->NewExternalArray(kElementCount,
16208 v8::kExternalUint8ClampedArray,
16210 // Force GC to trigger verification.
16211 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16212 for (int i = 0; i < kElementCount; i++) {
16213 pixels->set(i, i % 256);
16215 // Force GC to trigger verification.
16216 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16217 for (int i = 0; i < kElementCount; i++) {
16218 CHECK_EQ(i % 256, pixels->get_scalar(i));
16219 CHECK_EQ(i % 256, pixel_data[i]);
16222 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16223 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16224 // Set the elements to be the pixels.
16225 // jsobj->set_elements(*pixels);
16226 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16227 CheckElementValue(isolate, 1, jsobj, 1);
16228 obj->Set(v8_str("field"), v8::Int32::New(CcTest::isolate(), 1503));
16229 context->Global()->Set(v8_str("pixels"), obj);
16230 v8::Handle<v8::Value> result = CompileRun("pixels.field");
16231 CHECK_EQ(1503, result->Int32Value());
16232 result = CompileRun("pixels[1]");
16233 CHECK_EQ(1, result->Int32Value());
16235 result = CompileRun("var sum = 0;"
16236 "for (var i = 0; i < 8; i++) {"
16237 " sum += pixels[i] = pixels[i] = -i;"
16240 CHECK_EQ(-28, result->Int32Value());
16242 result = CompileRun("var sum = 0;"
16243 "for (var i = 0; i < 8; i++) {"
16244 " sum += pixels[i] = pixels[i] = 0;"
16247 CHECK_EQ(0, result->Int32Value());
16249 result = CompileRun("var sum = 0;"
16250 "for (var i = 0; i < 8; i++) {"
16251 " sum += pixels[i] = pixels[i] = 255;"
16254 CHECK_EQ(8 * 255, result->Int32Value());
16256 result = CompileRun("var sum = 0;"
16257 "for (var i = 0; i < 8; i++) {"
16258 " sum += pixels[i] = pixels[i] = 256 + i;"
16261 CHECK_EQ(2076, result->Int32Value());
16263 result = CompileRun("var sum = 0;"
16264 "for (var i = 0; i < 8; i++) {"
16265 " sum += pixels[i] = pixels[i] = i;"
16268 CHECK_EQ(28, result->Int32Value());
16270 result = CompileRun("var sum = 0;"
16271 "for (var i = 0; i < 8; i++) {"
16272 " sum += pixels[i];"
16275 CHECK_EQ(28, result->Int32Value());
16277 i::Handle<i::Smi> value(i::Smi::FromInt(2),
16278 reinterpret_cast<i::Isolate*>(context->GetIsolate()));
16279 i::Handle<i::Object> no_failure;
16280 no_failure = i::JSObject::SetElement(
16281 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16282 DCHECK(!no_failure.is_null());
16284 CheckElementValue(isolate, 2, jsobj, 1);
16285 *value.location() = i::Smi::FromInt(256);
16286 no_failure = i::JSObject::SetElement(
16287 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16288 DCHECK(!no_failure.is_null());
16290 CheckElementValue(isolate, 255, jsobj, 1);
16291 *value.location() = i::Smi::FromInt(-1);
16292 no_failure = i::JSObject::SetElement(
16293 jsobj, 1, value, NONE, i::SLOPPY).ToHandleChecked();
16294 DCHECK(!no_failure.is_null());
16296 CheckElementValue(isolate, 0, jsobj, 1);
16298 result = CompileRun("for (var i = 0; i < 8; i++) {"
16299 " pixels[i] = (i * 65) - 109;"
16301 "pixels[1] + pixels[6];");
16302 CHECK_EQ(255, result->Int32Value());
16303 CheckElementValue(isolate, 0, jsobj, 0);
16304 CheckElementValue(isolate, 0, jsobj, 1);
16305 CheckElementValue(isolate, 21, jsobj, 2);
16306 CheckElementValue(isolate, 86, jsobj, 3);
16307 CheckElementValue(isolate, 151, jsobj, 4);
16308 CheckElementValue(isolate, 216, jsobj, 5);
16309 CheckElementValue(isolate, 255, jsobj, 6);
16310 CheckElementValue(isolate, 255, jsobj, 7);
16311 result = CompileRun("var sum = 0;"
16312 "for (var i = 0; i < 8; i++) {"
16313 " sum += pixels[i];"
16316 CHECK_EQ(984, result->Int32Value());
16318 result = CompileRun("for (var i = 0; i < 8; i++) {"
16319 " pixels[i] = (i * 1.1);"
16321 "pixels[1] + pixels[6];");
16322 CHECK_EQ(8, result->Int32Value());
16323 CheckElementValue(isolate, 0, jsobj, 0);
16324 CheckElementValue(isolate, 1, jsobj, 1);
16325 CheckElementValue(isolate, 2, jsobj, 2);
16326 CheckElementValue(isolate, 3, jsobj, 3);
16327 CheckElementValue(isolate, 4, jsobj, 4);
16328 CheckElementValue(isolate, 6, jsobj, 5);
16329 CheckElementValue(isolate, 7, jsobj, 6);
16330 CheckElementValue(isolate, 8, jsobj, 7);
16332 result = CompileRun("for (var i = 0; i < 8; i++) {"
16333 " pixels[7] = undefined;"
16336 CHECK_EQ(0, result->Int32Value());
16337 CheckElementValue(isolate, 0, jsobj, 7);
16339 result = CompileRun("for (var i = 0; i < 8; i++) {"
16340 " pixels[6] = '2.3';"
16343 CHECK_EQ(2, result->Int32Value());
16344 CheckElementValue(isolate, 2, jsobj, 6);
16346 result = CompileRun("for (var i = 0; i < 8; i++) {"
16347 " pixels[5] = NaN;"
16350 CHECK_EQ(0, result->Int32Value());
16351 CheckElementValue(isolate, 0, jsobj, 5);
16353 result = CompileRun("for (var i = 0; i < 8; i++) {"
16354 " pixels[8] = Infinity;"
16357 CHECK_EQ(255, result->Int32Value());
16358 CheckElementValue(isolate, 255, jsobj, 8);
16360 result = CompileRun("for (var i = 0; i < 8; i++) {"
16361 " pixels[9] = -Infinity;"
16364 CHECK_EQ(0, result->Int32Value());
16365 CheckElementValue(isolate, 0, jsobj, 9);
16367 result = CompileRun("pixels[3] = 33;"
16368 "delete pixels[3];"
16370 CHECK_EQ(33, result->Int32Value());
16372 result = CompileRun("pixels[0] = 10; pixels[1] = 11;"
16373 "pixels[2] = 12; pixels[3] = 13;"
16374 "pixels.__defineGetter__('2',"
16375 "function() { return 120; });"
16377 CHECK_EQ(12, result->Int32Value());
16379 result = CompileRun("var js_array = new Array(40);"
16380 "js_array[0] = 77;"
16382 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16384 result = CompileRun("pixels[1] = 23;"
16385 "pixels.__proto__ = [];"
16386 "js_array.__proto__ = pixels;"
16387 "js_array.concat(pixels);");
16388 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16389 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16391 result = CompileRun("pixels[1] = 23;");
16392 CHECK_EQ(23, result->Int32Value());
16394 // Test for index greater than 255. Regression test for:
16395 // http://code.google.com/p/chromium/issues/detail?id=26337.
16396 result = CompileRun("pixels[256] = 255;");
16397 CHECK_EQ(255, result->Int32Value());
16398 result = CompileRun("var i = 0;"
16399 "for (var j = 0; j < 8; j++) { i = pixels[256]; }"
16401 CHECK_EQ(255, result->Int32Value());
16403 // Make sure that pixel array ICs recognize when a non-pixel array
16404 // is passed to it.
16405 result = CompileRun("function pa_load(p) {"
16407 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16410 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16411 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16412 "just_ints = new Object();"
16413 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16414 "for (var i = 0; i < 10; ++i) {"
16415 " result = pa_load(just_ints);"
16418 CHECK_EQ(32640, result->Int32Value());
16420 // Make sure that pixel array ICs recognize out-of-bound accesses.
16421 result = CompileRun("function pa_load(p, start) {"
16423 " for (var j = start; j < 256; j++) { sum += p[j]; }"
16426 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16427 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16428 "for (var i = 0; i < 10; ++i) {"
16429 " result = pa_load(pixels,-10);"
16432 CHECK_EQ(0, result->Int32Value());
16434 // Make sure that generic ICs properly handles a pixel array.
16435 result = CompileRun("function pa_load(p) {"
16437 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16440 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16441 "just_ints = new Object();"
16442 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16443 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16444 "for (var i = 0; i < 10; ++i) {"
16445 " result = pa_load(pixels);"
16448 CHECK_EQ(32640, result->Int32Value());
16450 // Make sure that generic load ICs recognize out-of-bound accesses in
16452 result = CompileRun("function pa_load(p, start) {"
16454 " for (var j = start; j < 256; j++) { sum += p[j]; }"
16457 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16458 "just_ints = new Object();"
16459 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16460 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }"
16461 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }"
16462 "for (var i = 0; i < 10; ++i) {"
16463 " result = pa_load(pixels,-10);"
16466 CHECK_EQ(0, result->Int32Value());
16468 // Make sure that generic ICs properly handles other types than pixel
16469 // arrays (that the inlined fast pixel array test leaves the right information
16470 // in the right registers).
16471 result = CompileRun("function pa_load(p) {"
16473 " for (var j = 0; j < 256; j++) { sum += p[j]; }"
16476 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16477 "just_ints = new Object();"
16478 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16479 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }"
16480 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }"
16481 "sparse_array = new Object();"
16482 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }"
16483 "sparse_array[1000000] = 3;"
16484 "for (var i = 0; i < 10; ++i) {"
16485 " result = pa_load(sparse_array);"
16488 CHECK_EQ(32640, result->Int32Value());
16490 // Make sure that pixel array store ICs clamp values correctly.
16491 result = CompileRun("function pa_store(p) {"
16492 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16494 "pa_store(pixels);"
16496 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16498 CHECK_EQ(48896, result->Int32Value());
16500 // Make sure that pixel array stores correctly handle accesses outside
16501 // of the pixel array..
16502 result = CompileRun("function pa_store(p,start) {"
16503 " for (var j = 0; j < 256; j++) {"
16504 " p[j+start] = j * 2;"
16507 "pa_store(pixels,0);"
16508 "pa_store(pixels,-128);"
16510 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16512 CHECK_EQ(65280, result->Int32Value());
16514 // Make sure that the generic store stub correctly handle accesses outside
16515 // of the pixel array..
16516 result = CompileRun("function pa_store(p,start) {"
16517 " for (var j = 0; j < 256; j++) {"
16518 " p[j+start] = j * 2;"
16521 "pa_store(pixels,0);"
16522 "just_ints = new Object();"
16523 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }"
16524 "pa_store(just_ints, 0);"
16525 "pa_store(pixels,-128);"
16527 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16529 CHECK_EQ(65280, result->Int32Value());
16531 // Make sure that the generic keyed store stub clamps pixel array values
16533 result = CompileRun("function pa_store(p) {"
16534 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }"
16536 "pa_store(pixels);"
16537 "just_ints = new Object();"
16538 "pa_store(just_ints);"
16539 "pa_store(pixels);"
16541 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }"
16543 CHECK_EQ(48896, result->Int32Value());
16545 // Make sure that pixel array loads are optimized by crankshaft.
16546 result = CompileRun("function pa_load(p) {"
16548 " for (var i=0; i<256; ++i) {"
16553 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }"
16554 "for (var i = 0; i < 5000; ++i) {"
16555 " result = pa_load(pixels);"
16558 CHECK_EQ(32640, result->Int32Value());
16560 // Make sure that pixel array stores are optimized by crankshaft.
16561 result = CompileRun("function pa_init(p) {"
16562 "for (var i = 0; i < 256; ++i) { p[i] = i; }"
16564 "function pa_load(p) {"
16566 " for (var i=0; i<256; ++i) {"
16571 "for (var i = 0; i < 5000; ++i) {"
16572 " pa_init(pixels);"
16574 "result = pa_load(pixels);"
16576 CHECK_EQ(32640, result->Int32Value());
16582 THREADED_TEST(PixelArrayInfo) {
16583 LocalContext context;
16584 v8::HandleScope scope(context->GetIsolate());
16585 for (int size = 0; size < 100; size += 10) {
16586 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size));
16587 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
16588 obj->SetIndexedPropertiesToPixelData(pixel_data, size);
16589 CHECK(obj->HasIndexedPropertiesInPixelData());
16590 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData());
16591 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength());
16597 static void NotHandledIndexedPropertyGetter(
16599 const v8::PropertyCallbackInfo<v8::Value>& info) {
16600 ApiTestFuzzer::Fuzz();
16604 static void NotHandledIndexedPropertySetter(
16606 Local<Value> value,
16607 const v8::PropertyCallbackInfo<v8::Value>& info) {
16608 ApiTestFuzzer::Fuzz();
16612 THREADED_TEST(PixelArrayWithInterceptor) {
16613 LocalContext context;
16614 i::Factory* factory = CcTest::i_isolate()->factory();
16615 v8::Isolate* isolate = context->GetIsolate();
16616 v8::HandleScope scope(isolate);
16617 const int kElementCount = 260;
16618 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount));
16619 i::Handle<i::ExternalUint8ClampedArray> pixels =
16620 i::Handle<i::ExternalUint8ClampedArray>::cast(
16621 factory->NewExternalArray(kElementCount,
16622 v8::kExternalUint8ClampedArray,
16624 for (int i = 0; i < kElementCount; i++) {
16625 pixels->set(i, i % 256);
16627 v8::Handle<v8::ObjectTemplate> templ =
16628 v8::ObjectTemplate::New(context->GetIsolate());
16629 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
16630 NotHandledIndexedPropertySetter);
16631 v8::Handle<v8::Object> obj = templ->NewInstance();
16632 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
16633 context->Global()->Set(v8_str("pixels"), obj);
16634 v8::Handle<v8::Value> result = CompileRun("pixels[1]");
16635 CHECK_EQ(1, result->Int32Value());
16636 result = CompileRun("var sum = 0;"
16637 "for (var i = 0; i < 8; i++) {"
16638 " sum += pixels[i] = pixels[i] = -i;"
16641 CHECK_EQ(-28, result->Int32Value());
16642 result = CompileRun("pixels.hasOwnProperty('1')");
16643 CHECK(result->BooleanValue());
16648 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) {
16649 switch (array_type) {
16650 case v8::kExternalInt8Array:
16651 case v8::kExternalUint8Array:
16652 case v8::kExternalUint8ClampedArray:
16655 case v8::kExternalInt16Array:
16656 case v8::kExternalUint16Array:
16659 case v8::kExternalInt32Array:
16660 case v8::kExternalUint32Array:
16661 case v8::kExternalFloat32Array:
16664 case v8::kExternalFloat64Array:
16676 template <class ExternalArrayClass, class ElementType>
16677 static void ObjectWithExternalArrayTestHelper(
16678 Handle<Context> context,
16679 v8::Handle<Object> obj,
16681 v8::ExternalArrayType array_type,
16682 int64_t low, int64_t high) {
16683 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
16684 i::Isolate* isolate = jsobj->GetIsolate();
16685 obj->Set(v8_str("field"),
16686 v8::Int32::New(reinterpret_cast<v8::Isolate*>(isolate), 1503));
16687 context->Global()->Set(v8_str("ext_array"), obj);
16688 v8::Handle<v8::Value> result = CompileRun("ext_array.field");
16689 CHECK_EQ(1503, result->Int32Value());
16690 result = CompileRun("ext_array[1]");
16691 CHECK_EQ(1, result->Int32Value());
16693 // Check assigned smis
16694 result = CompileRun("for (var i = 0; i < 8; i++) {"
16695 " ext_array[i] = i;"
16698 "for (var i = 0; i < 8; i++) {"
16699 " sum += ext_array[i];"
16703 CHECK_EQ(28, result->Int32Value());
16704 // Check pass through of assigned smis
16705 result = CompileRun("var sum = 0;"
16706 "for (var i = 0; i < 8; i++) {"
16707 " sum += ext_array[i] = ext_array[i] = -i;"
16710 CHECK_EQ(-28, result->Int32Value());
16713 // Check assigned smis in reverse order
16714 result = CompileRun("for (var i = 8; --i >= 0; ) {"
16715 " ext_array[i] = i;"
16718 "for (var i = 0; i < 8; i++) {"
16719 " sum += ext_array[i];"
16722 CHECK_EQ(28, result->Int32Value());
16724 // Check pass through of assigned HeapNumbers
16725 result = CompileRun("var sum = 0;"
16726 "for (var i = 0; i < 16; i+=2) {"
16727 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);"
16730 CHECK_EQ(-28, result->Int32Value());
16732 // Check assigned HeapNumbers
16733 result = CompileRun("for (var i = 0; i < 16; i+=2) {"
16734 " ext_array[i] = (i * 0.5);"
16737 "for (var i = 0; i < 16; i+=2) {"
16738 " sum += ext_array[i];"
16741 CHECK_EQ(28, result->Int32Value());
16743 // Check assigned HeapNumbers in reverse order
16744 result = CompileRun("for (var i = 14; i >= 0; i-=2) {"
16745 " ext_array[i] = (i * 0.5);"
16748 "for (var i = 0; i < 16; i+=2) {"
16749 " sum += ext_array[i];"
16752 CHECK_EQ(28, result->Int32Value());
16754 i::ScopedVector<char> test_buf(1024);
16756 // Check legal boundary conditions.
16757 // The repeated loads and stores ensure the ICs are exercised.
16758 const char* boundary_program =
16760 "for (var i = 0; i < 16; i++) {"
16761 " ext_array[i] = %lld;"
16763 " res = ext_array[i];"
16767 i::SNPrintF(test_buf,
16770 result = CompileRun(test_buf.start());
16771 CHECK_EQ(low, result->IntegerValue());
16773 i::SNPrintF(test_buf,
16776 result = CompileRun(test_buf.start());
16777 CHECK_EQ(high, result->IntegerValue());
16779 // Check misprediction of type in IC.
16780 result = CompileRun("var tmp_array = ext_array;"
16782 "for (var i = 0; i < 8; i++) {"
16783 " tmp_array[i] = i;"
16784 " sum += tmp_array[i];"
16790 // Force GC to trigger verification.
16791 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
16792 CHECK_EQ(28, result->Int32Value());
16794 // Make sure out-of-range loads do not throw.
16795 i::SNPrintF(test_buf,
16796 "var caught_exception = false;"
16800 " caught_exception = true;"
16802 "caught_exception;",
16804 result = CompileRun(test_buf.start());
16805 CHECK_EQ(false, result->BooleanValue());
16807 // Make sure out-of-range stores do not throw.
16808 i::SNPrintF(test_buf,
16809 "var caught_exception = false;"
16811 " ext_array[%d] = 1;"
16813 " caught_exception = true;"
16815 "caught_exception;",
16817 result = CompileRun(test_buf.start());
16818 CHECK_EQ(false, result->BooleanValue());
16820 // Check other boundary conditions, values and operations.
16821 result = CompileRun("for (var i = 0; i < 8; i++) {"
16822 " ext_array[7] = undefined;"
16825 CHECK_EQ(0, result->Int32Value());
16826 if (array_type == v8::kExternalFloat64Array ||
16827 array_type == v8::kExternalFloat32Array) {
16828 CHECK_EQ(static_cast<int>(v8::base::OS::nan_value()),
16830 i::Object::GetElement(
16831 isolate, jsobj, 7).ToHandleChecked()->Number()));
16833 CheckElementValue(isolate, 0, jsobj, 7);
16836 result = CompileRun("for (var i = 0; i < 8; i++) {"
16837 " ext_array[6] = '2.3';"
16840 CHECK_EQ(2, result->Int32Value());
16843 i::Object::GetElement(
16844 isolate, jsobj, 6).ToHandleChecked()->Number()));
16846 if (array_type != v8::kExternalFloat32Array &&
16847 array_type != v8::kExternalFloat64Array) {
16848 // Though the specification doesn't state it, be explicit about
16849 // converting NaNs and +/-Infinity to zero.
16850 result = CompileRun("for (var i = 0; i < 8; i++) {"
16851 " ext_array[i] = 5;"
16853 "for (var i = 0; i < 8; i++) {"
16854 " ext_array[i] = NaN;"
16857 CHECK_EQ(0, result->Int32Value());
16858 CheckElementValue(isolate, 0, jsobj, 5);
16860 result = CompileRun("for (var i = 0; i < 8; i++) {"
16861 " ext_array[i] = 5;"
16863 "for (var i = 0; i < 8; i++) {"
16864 " ext_array[i] = Infinity;"
16867 int expected_value =
16868 (array_type == v8::kExternalUint8ClampedArray) ? 255 : 0;
16869 CHECK_EQ(expected_value, result->Int32Value());
16870 CheckElementValue(isolate, expected_value, jsobj, 5);
16872 result = CompileRun("for (var i = 0; i < 8; i++) {"
16873 " ext_array[i] = 5;"
16875 "for (var i = 0; i < 8; i++) {"
16876 " ext_array[i] = -Infinity;"
16879 CHECK_EQ(0, result->Int32Value());
16880 CheckElementValue(isolate, 0, jsobj, 5);
16882 // Check truncation behavior of integral arrays.
16883 const char* unsigned_data =
16884 "var source_data = [0.6, 10.6];"
16885 "var expected_results = [0, 10];";
16886 const char* signed_data =
16887 "var source_data = [0.6, 10.6, -0.6, -10.6];"
16888 "var expected_results = [0, 10, 0, -10];";
16889 const char* pixel_data =
16890 "var source_data = [0.6, 10.6];"
16891 "var expected_results = [1, 11];";
16893 (array_type == v8::kExternalUint8Array ||
16894 array_type == v8::kExternalUint16Array ||
16895 array_type == v8::kExternalUint32Array);
16896 bool is_pixel_data = array_type == v8::kExternalUint8ClampedArray;
16898 i::SNPrintF(test_buf,
16900 "var all_passed = true;"
16901 "for (var i = 0; i < source_data.length; i++) {"
16902 " for (var j = 0; j < 8; j++) {"
16903 " ext_array[j] = source_data[i];"
16905 " all_passed = all_passed &&"
16906 " (ext_array[5] == expected_results[i]);"
16911 (is_pixel_data ? pixel_data : signed_data)));
16912 result = CompileRun(test_buf.start());
16913 CHECK_EQ(true, result->BooleanValue());
16916 i::Handle<ExternalArrayClass> array(
16917 ExternalArrayClass::cast(jsobj->elements()));
16918 for (int i = 0; i < element_count; i++) {
16919 array->set(i, static_cast<ElementType>(i));
16922 // Test complex assignments
16923 result = CompileRun("function ee_op_test_complex_func(sum) {"
16924 " for (var i = 0; i < 40; ++i) {"
16925 " sum += (ext_array[i] += 1);"
16926 " sum += (ext_array[i] -= 1);"
16931 "for (var i=0;i<10000;++i) {"
16932 " sum=ee_op_test_complex_func(sum);"
16935 CHECK_EQ(16000000, result->Int32Value());
16937 // Test count operations
16938 result = CompileRun("function ee_op_test_count_func(sum) {"
16939 " for (var i = 0; i < 40; ++i) {"
16940 " sum += (++ext_array[i]);"
16941 " sum += (--ext_array[i]);"
16946 "for (var i=0;i<10000;++i) {"
16947 " sum=ee_op_test_count_func(sum);"
16950 CHECK_EQ(16000000, result->Int32Value());
16952 result = CompileRun("ext_array[3] = 33;"
16953 "delete ext_array[3];"
16955 CHECK_EQ(33, result->Int32Value());
16957 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;"
16958 "ext_array[2] = 12; ext_array[3] = 13;"
16959 "ext_array.__defineGetter__('2',"
16960 "function() { return 120; });"
16962 CHECK_EQ(12, result->Int32Value());
16964 result = CompileRun("var js_array = new Array(40);"
16965 "js_array[0] = 77;"
16967 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16969 result = CompileRun("ext_array[1] = 23;"
16970 "ext_array.__proto__ = [];"
16971 "js_array.__proto__ = ext_array;"
16972 "js_array.concat(ext_array);");
16973 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value());
16974 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value());
16976 result = CompileRun("ext_array[1] = 23;");
16977 CHECK_EQ(23, result->Int32Value());
16981 template <class FixedTypedArrayClass,
16982 i::ElementsKind elements_kind,
16984 static void FixedTypedArrayTestHelper(
16985 v8::ExternalArrayType array_type,
16987 ElementType high) {
16988 i::FLAG_allow_natives_syntax = true;
16989 LocalContext context;
16990 i::Isolate* isolate = CcTest::i_isolate();
16991 i::Factory* factory = isolate->factory();
16992 v8::HandleScope scope(context->GetIsolate());
16993 const int kElementCount = 260;
16994 i::Handle<FixedTypedArrayClass> fixed_array =
16995 i::Handle<FixedTypedArrayClass>::cast(
16996 factory->NewFixedTypedArray(kElementCount, array_type));
16997 CHECK_EQ(FixedTypedArrayClass::kInstanceType,
16998 fixed_array->map()->instance_type());
16999 CHECK_EQ(kElementCount, fixed_array->length());
17000 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17001 for (int i = 0; i < kElementCount; i++) {
17002 fixed_array->set(i, static_cast<ElementType>(i));
17004 // Force GC to trigger verification.
17005 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17006 for (int i = 0; i < kElementCount; i++) {
17007 CHECK_EQ(static_cast<int64_t>(static_cast<ElementType>(i)),
17008 static_cast<int64_t>(fixed_array->get_scalar(i)));
17010 v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
17011 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17012 i::Handle<i::Map> fixed_array_map =
17013 i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
17014 jsobj->set_map(*fixed_array_map);
17015 jsobj->set_elements(*fixed_array);
17017 ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
17018 context.local(), obj, kElementCount, array_type,
17019 static_cast<int64_t>(low),
17020 static_cast<int64_t>(high));
17024 THREADED_TEST(FixedUint8Array) {
17025 FixedTypedArrayTestHelper<i::FixedUint8Array, i::UINT8_ELEMENTS, uint8_t>(
17026 v8::kExternalUint8Array,
17031 THREADED_TEST(FixedUint8ClampedArray) {
17032 FixedTypedArrayTestHelper<i::FixedUint8ClampedArray,
17033 i::UINT8_CLAMPED_ELEMENTS, uint8_t>(
17034 v8::kExternalUint8ClampedArray,
17039 THREADED_TEST(FixedInt8Array) {
17040 FixedTypedArrayTestHelper<i::FixedInt8Array, i::INT8_ELEMENTS, int8_t>(
17041 v8::kExternalInt8Array,
17046 THREADED_TEST(FixedUint16Array) {
17047 FixedTypedArrayTestHelper<i::FixedUint16Array, i::UINT16_ELEMENTS, uint16_t>(
17048 v8::kExternalUint16Array,
17053 THREADED_TEST(FixedInt16Array) {
17054 FixedTypedArrayTestHelper<i::FixedInt16Array, i::INT16_ELEMENTS, int16_t>(
17055 v8::kExternalInt16Array,
17060 THREADED_TEST(FixedUint32Array) {
17061 FixedTypedArrayTestHelper<i::FixedUint32Array, i::UINT32_ELEMENTS, uint32_t>(
17062 v8::kExternalUint32Array,
17067 THREADED_TEST(FixedInt32Array) {
17068 FixedTypedArrayTestHelper<i::FixedInt32Array, i::INT32_ELEMENTS, int32_t>(
17069 v8::kExternalInt32Array,
17074 THREADED_TEST(FixedFloat32Array) {
17075 FixedTypedArrayTestHelper<i::FixedFloat32Array, i::FLOAT32_ELEMENTS, float>(
17076 v8::kExternalFloat32Array,
17081 THREADED_TEST(FixedFloat64Array) {
17082 FixedTypedArrayTestHelper<i::FixedFloat64Array, i::FLOAT64_ELEMENTS, float>(
17083 v8::kExternalFloat64Array,
17088 template <class ExternalArrayClass, class ElementType>
17089 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type,
17092 LocalContext context;
17093 i::Isolate* isolate = CcTest::i_isolate();
17094 i::Factory* factory = isolate->factory();
17095 v8::HandleScope scope(context->GetIsolate());
17096 const int kElementCount = 40;
17097 int element_size = ExternalArrayElementSize(array_type);
17098 ElementType* array_data =
17099 static_cast<ElementType*>(malloc(kElementCount * element_size));
17100 i::Handle<ExternalArrayClass> array =
17101 i::Handle<ExternalArrayClass>::cast(
17102 factory->NewExternalArray(kElementCount, array_type, array_data));
17103 // Force GC to trigger verification.
17104 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17105 for (int i = 0; i < kElementCount; i++) {
17106 array->set(i, static_cast<ElementType>(i));
17108 // Force GC to trigger verification.
17109 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
17110 for (int i = 0; i < kElementCount; i++) {
17111 CHECK_EQ(static_cast<int64_t>(i),
17112 static_cast<int64_t>(array->get_scalar(i)));
17113 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i]));
17116 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17117 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
17118 // Set the elements to be the external array.
17119 obj->SetIndexedPropertiesToExternalArrayData(array_data,
17124 i::Object::GetElement(
17125 isolate, jsobj, 1).ToHandleChecked()->Number()));
17127 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17128 context.local(), obj, kElementCount, array_type, low, high);
17130 v8::Handle<v8::Value> result;
17132 // Test more complex manipulations which cause eax to contain values
17133 // that won't be completely overwritten by loads from the arrays.
17134 // This catches bugs in the instructions used for the KeyedLoadIC
17135 // for byte and word types.
17137 const int kXSize = 300;
17138 const int kYSize = 300;
17139 const int kLargeElementCount = kXSize * kYSize * 4;
17140 ElementType* large_array_data =
17141 static_cast<ElementType*>(malloc(kLargeElementCount * element_size));
17142 v8::Handle<v8::Object> large_obj = v8::Object::New(context->GetIsolate());
17143 // Set the elements to be the external array.
17144 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data,
17146 kLargeElementCount);
17147 context->Global()->Set(v8_str("large_array"), large_obj);
17148 // Initialize contents of a few rows.
17149 for (int x = 0; x < 300; x++) {
17151 int offset = row * 300 * 4;
17152 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17153 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17154 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17155 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17157 offset = row * 300 * 4;
17158 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17159 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17160 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17161 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17163 offset = row * 300 * 4;
17164 large_array_data[offset + 4 * x + 0] = (ElementType) 127;
17165 large_array_data[offset + 4 * x + 1] = (ElementType) 0;
17166 large_array_data[offset + 4 * x + 2] = (ElementType) 0;
17167 large_array_data[offset + 4 * x + 3] = (ElementType) 127;
17169 // The goal of the code below is to make "offset" large enough
17170 // that the computation of the index (which goes into eax) has
17171 // high bits set which will not be overwritten by a byte or short
17173 result = CompileRun("var failed = false;"
17175 "for (var i = 0; i < 300; i++) {"
17176 " if (large_array[4 * i] != 127 ||"
17177 " large_array[4 * i + 1] != 0 ||"
17178 " large_array[4 * i + 2] != 0 ||"
17179 " large_array[4 * i + 3] != 127) {"
17183 "offset = 150 * 300 * 4;"
17184 "for (var i = 0; i < 300; i++) {"
17185 " if (large_array[offset + 4 * i] != 127 ||"
17186 " large_array[offset + 4 * i + 1] != 0 ||"
17187 " large_array[offset + 4 * i + 2] != 0 ||"
17188 " large_array[offset + 4 * i + 3] != 127) {"
17192 "offset = 298 * 300 * 4;"
17193 "for (var i = 0; i < 300; i++) {"
17194 " if (large_array[offset + 4 * i] != 127 ||"
17195 " large_array[offset + 4 * i + 1] != 0 ||"
17196 " large_array[offset + 4 * i + 2] != 0 ||"
17197 " large_array[offset + 4 * i + 3] != 127) {"
17202 CHECK_EQ(true, result->BooleanValue());
17203 free(large_array_data);
17206 // The "" property descriptor is overloaded to store information about
17207 // the external array. Ensure that setting and accessing the "" property
17208 // works (it should overwrite the information cached about the external
17209 // array in the DescriptorArray) in various situations.
17210 result = CompileRun("ext_array[''] = 23; ext_array['']");
17211 CHECK_EQ(23, result->Int32Value());
17213 // Property "" set after the external array is associated with the object.
17215 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17216 obj2->Set(v8_str("ee_test_field"),
17217 v8::Int32::New(context->GetIsolate(), 256));
17218 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
17219 // Set the elements to be the external array.
17220 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17223 context->Global()->Set(v8_str("ext_array"), obj2);
17224 result = CompileRun("ext_array['']");
17225 CHECK_EQ(1503, result->Int32Value());
17228 // Property "" set after the external array is associated with the object.
17230 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17231 obj2->Set(v8_str("ee_test_field_2"),
17232 v8::Int32::New(context->GetIsolate(), 256));
17233 // Set the elements to be the external array.
17234 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17237 obj2->Set(v8_str(""), v8::Int32::New(context->GetIsolate(), 1503));
17238 context->Global()->Set(v8_str("ext_array"), obj2);
17239 result = CompileRun("ext_array['']");
17240 CHECK_EQ(1503, result->Int32Value());
17243 // Should reuse the map from previous test.
17245 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17246 obj2->Set(v8_str("ee_test_field_2"),
17247 v8::Int32::New(context->GetIsolate(), 256));
17248 // Set the elements to be the external array. Should re-use the map
17249 // from previous test.
17250 obj2->SetIndexedPropertiesToExternalArrayData(array_data,
17253 context->Global()->Set(v8_str("ext_array"), obj2);
17254 result = CompileRun("ext_array['']");
17257 // Property "" is a constant function that shouldn't not be interfered with
17258 // when an external array is set.
17260 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17262 obj2->Set(v8_str("ee_test_field3"),
17263 v8::Int32::New(context->GetIsolate(), 256));
17265 // Add a constant function to an object.
17266 context->Global()->Set(v8_str("ext_array"), obj2);
17267 result = CompileRun("ext_array[''] = function() {return 1503;};"
17268 "ext_array['']();");
17270 // Add an external array transition to the same map that
17271 // has the constant transition.
17272 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
17273 obj3->Set(v8_str("ee_test_field3"),
17274 v8::Int32::New(context->GetIsolate(), 256));
17275 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
17278 context->Global()->Set(v8_str("ext_array"), obj3);
17281 // If a external array transition is in the map, it should get clobbered
17282 // by a constant function.
17284 // Add an external array transition.
17285 v8::Handle<v8::Object> obj3 = v8::Object::New(context->GetIsolate());
17286 obj3->Set(v8_str("ee_test_field4"),
17287 v8::Int32::New(context->GetIsolate(), 256));
17288 obj3->SetIndexedPropertiesToExternalArrayData(array_data,
17292 // Add a constant function to the same map that just got an external array
17294 v8::Handle<v8::Object> obj2 = v8::Object::New(context->GetIsolate());
17295 obj2->Set(v8_str("ee_test_field4"),
17296 v8::Int32::New(context->GetIsolate(), 256));
17297 context->Global()->Set(v8_str("ext_array"), obj2);
17298 result = CompileRun("ext_array[''] = function() {return 1503;};"
17299 "ext_array['']();");
17306 THREADED_TEST(ExternalInt8Array) {
17307 ExternalArrayTestHelper<i::ExternalInt8Array, int8_t>(
17308 v8::kExternalInt8Array,
17314 THREADED_TEST(ExternalUint8Array) {
17315 ExternalArrayTestHelper<i::ExternalUint8Array, uint8_t>(
17316 v8::kExternalUint8Array,
17322 THREADED_TEST(ExternalUint8ClampedArray) {
17323 ExternalArrayTestHelper<i::ExternalUint8ClampedArray, uint8_t>(
17324 v8::kExternalUint8ClampedArray,
17330 THREADED_TEST(ExternalInt16Array) {
17331 ExternalArrayTestHelper<i::ExternalInt16Array, int16_t>(
17332 v8::kExternalInt16Array,
17338 THREADED_TEST(ExternalUint16Array) {
17339 ExternalArrayTestHelper<i::ExternalUint16Array, uint16_t>(
17340 v8::kExternalUint16Array,
17346 THREADED_TEST(ExternalInt32Array) {
17347 ExternalArrayTestHelper<i::ExternalInt32Array, int32_t>(
17348 v8::kExternalInt32Array,
17349 INT_MIN, // -2147483648
17350 INT_MAX); // 2147483647
17354 THREADED_TEST(ExternalUint32Array) {
17355 ExternalArrayTestHelper<i::ExternalUint32Array, uint32_t>(
17356 v8::kExternalUint32Array,
17358 UINT_MAX); // 4294967295
17362 THREADED_TEST(ExternalFloat32Array) {
17363 ExternalArrayTestHelper<i::ExternalFloat32Array, float>(
17364 v8::kExternalFloat32Array,
17370 THREADED_TEST(ExternalFloat64Array) {
17371 ExternalArrayTestHelper<i::ExternalFloat64Array, double>(
17372 v8::kExternalFloat64Array,
17378 THREADED_TEST(ExternalArrays) {
17379 TestExternalInt8Array();
17380 TestExternalUint8Array();
17381 TestExternalInt16Array();
17382 TestExternalUint16Array();
17383 TestExternalInt32Array();
17384 TestExternalUint32Array();
17385 TestExternalFloat32Array();
17389 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) {
17390 LocalContext context;
17391 v8::HandleScope scope(context->GetIsolate());
17392 for (int size = 0; size < 100; size += 10) {
17393 int element_size = ExternalArrayElementSize(array_type);
17394 void* external_data = malloc(size * element_size);
17395 v8::Handle<v8::Object> obj = v8::Object::New(context->GetIsolate());
17396 obj->SetIndexedPropertiesToExternalArrayData(
17397 external_data, array_type, size);
17398 CHECK(obj->HasIndexedPropertiesInExternalArrayData());
17399 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData());
17400 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType());
17401 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength());
17402 free(external_data);
17407 THREADED_TEST(ExternalArrayInfo) {
17408 ExternalArrayInfoTestHelper(v8::kExternalInt8Array);
17409 ExternalArrayInfoTestHelper(v8::kExternalUint8Array);
17410 ExternalArrayInfoTestHelper(v8::kExternalInt16Array);
17411 ExternalArrayInfoTestHelper(v8::kExternalUint16Array);
17412 ExternalArrayInfoTestHelper(v8::kExternalInt32Array);
17413 ExternalArrayInfoTestHelper(v8::kExternalUint32Array);
17414 ExternalArrayInfoTestHelper(v8::kExternalFloat32Array);
17415 ExternalArrayInfoTestHelper(v8::kExternalFloat64Array);
17416 ExternalArrayInfoTestHelper(v8::kExternalUint8ClampedArray);
17420 void ExtArrayLimitsHelper(v8::Isolate* isolate,
17421 v8::ExternalArrayType array_type,
17423 v8::Handle<v8::Object> obj = v8::Object::New(isolate);
17424 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
17425 last_location = last_message = NULL;
17426 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size);
17427 CHECK(!obj->HasIndexedPropertiesInExternalArrayData());
17428 CHECK_NE(NULL, last_location);
17429 CHECK_NE(NULL, last_message);
17433 TEST(ExternalArrayLimits) {
17434 LocalContext context;
17435 v8::Isolate* isolate = context->GetIsolate();
17436 v8::HandleScope scope(isolate);
17437 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0x40000000);
17438 ExtArrayLimitsHelper(isolate, v8::kExternalInt8Array, 0xffffffff);
17439 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0x40000000);
17440 ExtArrayLimitsHelper(isolate, v8::kExternalUint8Array, 0xffffffff);
17441 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0x40000000);
17442 ExtArrayLimitsHelper(isolate, v8::kExternalInt16Array, 0xffffffff);
17443 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0x40000000);
17444 ExtArrayLimitsHelper(isolate, v8::kExternalUint16Array, 0xffffffff);
17445 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0x40000000);
17446 ExtArrayLimitsHelper(isolate, v8::kExternalInt32Array, 0xffffffff);
17447 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0x40000000);
17448 ExtArrayLimitsHelper(isolate, v8::kExternalUint32Array, 0xffffffff);
17449 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0x40000000);
17450 ExtArrayLimitsHelper(isolate, v8::kExternalFloat32Array, 0xffffffff);
17451 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0x40000000);
17452 ExtArrayLimitsHelper(isolate, v8::kExternalFloat64Array, 0xffffffff);
17453 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0x40000000);
17454 ExtArrayLimitsHelper(isolate, v8::kExternalUint8ClampedArray, 0xffffffff);
17458 template <typename ElementType, typename TypedArray,
17459 class ExternalArrayClass>
17460 void TypedArrayTestHelper(v8::ExternalArrayType array_type,
17461 int64_t low, int64_t high) {
17462 const int kElementCount = 50;
17464 i::ScopedVector<ElementType> backing_store(kElementCount+2);
17467 v8::Isolate* isolate = env->GetIsolate();
17468 v8::HandleScope handle_scope(isolate);
17470 Local<v8::ArrayBuffer> ab =
17471 v8::ArrayBuffer::New(isolate, backing_store.start(),
17472 (kElementCount + 2) * sizeof(ElementType));
17473 Local<TypedArray> ta =
17474 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount);
17475 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta);
17476 CHECK_EQ(kElementCount, static_cast<int>(ta->Length()));
17477 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset()));
17478 CHECK_EQ(kElementCount*sizeof(ElementType),
17479 static_cast<int>(ta->ByteLength()));
17480 CHECK_EQ(ab, ta->Buffer());
17482 ElementType* data = backing_store.start() + 2;
17483 for (int i = 0; i < kElementCount; i++) {
17484 data[i] = static_cast<ElementType>(i);
17487 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>(
17488 env.local(), ta, kElementCount, array_type, low, high);
17492 THREADED_TEST(Uint8Array) {
17493 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUint8Array>(
17494 v8::kExternalUint8Array, 0, 0xFF);
17498 THREADED_TEST(Int8Array) {
17499 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalInt8Array>(
17500 v8::kExternalInt8Array, -0x80, 0x7F);
17504 THREADED_TEST(Uint16Array) {
17505 TypedArrayTestHelper<uint16_t,
17507 i::ExternalUint16Array>(
17508 v8::kExternalUint16Array, 0, 0xFFFF);
17512 THREADED_TEST(Int16Array) {
17513 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalInt16Array>(
17514 v8::kExternalInt16Array, -0x8000, 0x7FFF);
17518 THREADED_TEST(Uint32Array) {
17519 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUint32Array>(
17520 v8::kExternalUint32Array, 0, UINT_MAX);
17524 THREADED_TEST(Int32Array) {
17525 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalInt32Array>(
17526 v8::kExternalInt32Array, INT_MIN, INT_MAX);
17530 THREADED_TEST(Float32Array) {
17531 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloat32Array>(
17532 v8::kExternalFloat32Array, -500, 500);
17536 THREADED_TEST(Float64Array) {
17537 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalFloat64Array>(
17538 v8::kExternalFloat64Array, -500, 500);
17542 THREADED_TEST(Uint8ClampedArray) {
17543 TypedArrayTestHelper<uint8_t,
17544 v8::Uint8ClampedArray, i::ExternalUint8ClampedArray>(
17545 v8::kExternalUint8ClampedArray, 0, 0xFF);
17549 THREADED_TEST(DataView) {
17550 const int kSize = 50;
17552 i::ScopedVector<uint8_t> backing_store(kSize+2);
17555 v8::Isolate* isolate = env->GetIsolate();
17556 v8::HandleScope handle_scope(isolate);
17558 Local<v8::ArrayBuffer> ab =
17559 v8::ArrayBuffer::New(isolate, backing_store.start(), 2 + kSize);
17560 Local<v8::DataView> dv =
17561 v8::DataView::New(ab, 2, kSize);
17562 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv);
17563 CHECK_EQ(2, static_cast<int>(dv->ByteOffset()));
17564 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength()));
17565 CHECK_EQ(ab, dv->Buffer());
17569 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \
17570 THREADED_TEST(Is##View) { \
17571 LocalContext env; \
17572 v8::Isolate* isolate = env->GetIsolate(); \
17573 v8::HandleScope handle_scope(isolate); \
17575 Handle<Value> result = CompileRun( \
17576 "var ab = new ArrayBuffer(128);" \
17577 "new " #View "(ab)"); \
17578 CHECK(result->IsArrayBufferView()); \
17579 CHECK(result->Is##View()); \
17580 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \
17583 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array)
17584 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array)
17585 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array)
17586 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array)
17587 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array)
17588 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array)
17589 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array)
17590 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array)
17591 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray)
17592 IS_ARRAY_BUFFER_VIEW_TEST(DataView)
17594 #undef IS_ARRAY_BUFFER_VIEW_TEST
17598 THREADED_TEST(ScriptContextDependence) {
17600 v8::HandleScope scope(c1->GetIsolate());
17601 const char *source = "foo";
17602 v8::Handle<v8::Script> dep = v8_compile(source);
17603 v8::ScriptCompiler::Source script_source(v8::String::NewFromUtf8(
17604 c1->GetIsolate(), source));
17605 v8::Handle<v8::UnboundScript> indep =
17606 v8::ScriptCompiler::CompileUnbound(c1->GetIsolate(), &script_source);
17607 c1->Global()->Set(v8::String::NewFromUtf8(c1->GetIsolate(), "foo"),
17608 v8::Integer::New(c1->GetIsolate(), 100));
17609 CHECK_EQ(dep->Run()->Int32Value(), 100);
17610 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 100);
17612 c2->Global()->Set(v8::String::NewFromUtf8(c2->GetIsolate(), "foo"),
17613 v8::Integer::New(c2->GetIsolate(), 101));
17614 CHECK_EQ(dep->Run()->Int32Value(), 100);
17615 CHECK_EQ(indep->BindToCurrentContext()->Run()->Int32Value(), 101);
17619 THREADED_TEST(StackTrace) {
17620 LocalContext context;
17621 v8::HandleScope scope(context->GetIsolate());
17622 v8::TryCatch try_catch;
17623 const char *source = "function foo() { FAIL.FAIL; }; foo();";
17624 v8::Handle<v8::String> src =
17625 v8::String::NewFromUtf8(context->GetIsolate(), source);
17626 v8::Handle<v8::String> origin =
17627 v8::String::NewFromUtf8(context->GetIsolate(), "stack-trace-test");
17628 v8::ScriptCompiler::Source script_source(src, v8::ScriptOrigin(origin));
17629 v8::ScriptCompiler::CompileUnbound(context->GetIsolate(), &script_source)
17630 ->BindToCurrentContext()
17632 CHECK(try_catch.HasCaught());
17633 v8::String::Utf8Value stack(try_catch.StackTrace());
17634 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL);
17638 // Checks that a StackFrame has certain expected values.
17639 void checkStackFrame(const char* expected_script_name,
17640 const char* expected_func_name, int expected_line_number,
17641 int expected_column, bool is_eval, bool is_constructor,
17642 v8::Handle<v8::StackFrame> frame) {
17643 v8::HandleScope scope(CcTest::isolate());
17644 v8::String::Utf8Value func_name(frame->GetFunctionName());
17645 v8::String::Utf8Value script_name(frame->GetScriptName());
17646 if (*script_name == NULL) {
17647 // The situation where there is no associated script, like for evals.
17648 CHECK(expected_script_name == NULL);
17650 CHECK(strstr(*script_name, expected_script_name) != NULL);
17652 CHECK(strstr(*func_name, expected_func_name) != NULL);
17653 CHECK_EQ(expected_line_number, frame->GetLineNumber());
17654 CHECK_EQ(expected_column, frame->GetColumn());
17655 CHECK_EQ(is_eval, frame->IsEval());
17656 CHECK_EQ(is_constructor, frame->IsConstructor());
17660 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) {
17661 v8::HandleScope scope(args.GetIsolate());
17662 const char* origin = "capture-stack-trace-test";
17663 const int kOverviewTest = 1;
17664 const int kDetailedTest = 2;
17666 DCHECK(args.Length() == 1);
17668 int testGroup = args[0]->Int32Value();
17669 if (testGroup == kOverviewTest) {
17670 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17671 args.GetIsolate(), 10, v8::StackTrace::kOverview);
17672 CHECK_EQ(4, stackTrace->GetFrameCount());
17673 checkStackFrame(origin, "bar", 2, 10, false, false,
17674 stackTrace->GetFrame(0));
17675 checkStackFrame(origin, "foo", 6, 3, false, false,
17676 stackTrace->GetFrame(1));
17677 // This is the source string inside the eval which has the call to foo.
17678 checkStackFrame(NULL, "", 1, 5, false, false,
17679 stackTrace->GetFrame(2));
17680 // The last frame is an anonymous function which has the initial eval call.
17681 checkStackFrame(origin, "", 8, 7, false, false,
17682 stackTrace->GetFrame(3));
17684 CHECK(stackTrace->AsArray()->IsArray());
17685 } else if (testGroup == kDetailedTest) {
17686 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
17687 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
17688 CHECK_EQ(4, stackTrace->GetFrameCount());
17689 checkStackFrame(origin, "bat", 4, 22, false, false,
17690 stackTrace->GetFrame(0));
17691 checkStackFrame(origin, "baz", 8, 3, false, true,
17692 stackTrace->GetFrame(1));
17693 bool is_eval = true;
17694 // This is the source string inside the eval which has the call to baz.
17695 checkStackFrame(NULL, "", 1, 5, is_eval, false,
17696 stackTrace->GetFrame(2));
17697 // The last frame is an anonymous function which has the initial eval call.
17698 checkStackFrame(origin, "", 10, 1, false, false,
17699 stackTrace->GetFrame(3));
17701 CHECK(stackTrace->AsArray()->IsArray());
17706 // Tests the C++ StackTrace API.
17707 // TODO(3074796): Reenable this as a THREADED_TEST once it passes.
17708 // THREADED_TEST(CaptureStackTrace) {
17709 TEST(CaptureStackTrace) {
17710 v8::Isolate* isolate = CcTest::isolate();
17711 v8::HandleScope scope(isolate);
17712 v8::Handle<v8::String> origin =
17713 v8::String::NewFromUtf8(isolate, "capture-stack-trace-test");
17714 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
17715 templ->Set(v8_str("AnalyzeStackInNativeCode"),
17716 v8::FunctionTemplate::New(isolate, AnalyzeStackInNativeCode));
17717 LocalContext context(0, templ);
17719 // Test getting OVERVIEW information. Should ignore information that is not
17720 // script name, function name, line number, and column offset.
17721 const char *overview_source =
17722 "function bar() {\n"
17723 " var y; AnalyzeStackInNativeCode(1);\n"
17725 "function foo() {\n"
17729 "var x;eval('new foo();');";
17730 v8::Handle<v8::String> overview_src =
17731 v8::String::NewFromUtf8(isolate, overview_source);
17732 v8::ScriptCompiler::Source script_source(overview_src,
17733 v8::ScriptOrigin(origin));
17734 v8::Handle<Value> overview_result(
17735 v8::ScriptCompiler::CompileUnbound(isolate, &script_source)
17736 ->BindToCurrentContext()
17738 CHECK(!overview_result.IsEmpty());
17739 CHECK(overview_result->IsObject());
17741 // Test getting DETAILED information.
17742 const char *detailed_source =
17743 "function bat() {AnalyzeStackInNativeCode(2);\n"
17746 "function baz() {\n"
17749 "eval('new baz();');";
17750 v8::Handle<v8::String> detailed_src =
17751 v8::String::NewFromUtf8(isolate, detailed_source);
17752 // Make the script using a non-zero line and column offset.
17753 v8::Handle<v8::Integer> line_offset = v8::Integer::New(isolate, 3);
17754 v8::Handle<v8::Integer> column_offset = v8::Integer::New(isolate, 5);
17755 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset);
17756 v8::ScriptCompiler::Source script_source2(detailed_src, detailed_origin);
17757 v8::Handle<v8::UnboundScript> detailed_script(
17758 v8::ScriptCompiler::CompileUnbound(isolate, &script_source2));
17759 v8::Handle<Value> detailed_result(
17760 detailed_script->BindToCurrentContext()->Run());
17761 CHECK(!detailed_result.IsEmpty());
17762 CHECK(detailed_result->IsObject());
17766 static void StackTraceForUncaughtExceptionListener(
17767 v8::Handle<v8::Message> message,
17768 v8::Handle<Value>) {
17770 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17771 CHECK_EQ(2, stack_trace->GetFrameCount());
17772 checkStackFrame("origin", "foo", 2, 3, false, false,
17773 stack_trace->GetFrame(0));
17774 checkStackFrame("origin", "bar", 5, 3, false, false,
17775 stack_trace->GetFrame(1));
17779 TEST(CaptureStackTraceForUncaughtException) {
17782 v8::HandleScope scope(env->GetIsolate());
17783 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17784 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17786 CompileRunWithOrigin(
17787 "function foo() {\n"
17790 "function bar() {\n"
17794 v8::Local<v8::Object> global = env->Global();
17795 Local<Value> trouble = global->Get(v8_str("bar"));
17796 CHECK(trouble->IsFunction());
17797 Function::Cast(*trouble)->Call(global, 0, NULL);
17798 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17799 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17800 CHECK_EQ(1, report_count);
17804 TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
17807 v8::HandleScope scope(env->GetIsolate());
17809 // Create an Error object first.
17810 CompileRunWithOrigin(
17811 "function foo() {\n"
17812 "e=new Error('err');\n"
17814 "function bar() {\n"
17819 v8::Local<v8::Object> global = env->Global();
17820 Local<Value> trouble = global->Get(v8_str("bar"));
17821 CHECK(trouble->IsFunction());
17822 Function::Cast(*trouble)->Call(global, 0, NULL);
17824 // Enable capturing detailed stack trace late, and throw the exception.
17825 // The detailed stack trace should be extracted from the simple stack.
17826 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
17827 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17828 CompileRunWithOrigin("throw e", "origin");
17829 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17830 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
17831 CHECK_EQ(1, report_count);
17835 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) {
17837 v8::HandleScope scope(env->GetIsolate());
17838 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true,
17840 v8::StackTrace::kDetailed);
17843 "var setters = ['column', 'lineNumber', 'scriptName',\n"
17844 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n"
17845 " 'isConstructor'];\n"
17846 "for (var i = 0; i < setters.length; i++) {\n"
17847 " var prop = setters[i];\n"
17848 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n"
17850 CompileRun("throw 'exception';");
17851 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17855 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message,
17856 v8::Handle<v8::Value> data) {
17857 // Use the frame where JavaScript is called from.
17858 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17859 CHECK(!stack_trace.IsEmpty());
17860 int frame_count = stack_trace->GetFrameCount();
17861 CHECK_EQ(3, frame_count);
17862 int line_number[] = {1, 2, 5};
17863 for (int i = 0; i < frame_count; i++) {
17864 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17869 // Test that we only return the stack trace at the site where the exception
17870 // is first thrown (not where it is rethrown).
17871 TEST(RethrowStackTrace) {
17873 v8::HandleScope scope(env->GetIsolate());
17874 // We make sure that
17875 // - the stack trace of the ReferenceError in g() is reported.
17876 // - the stack trace is not overwritten when e1 is rethrown by t().
17877 // - the stack trace of e2 does not overwrite that of e1.
17878 const char* source =
17879 "function g() { error; } \n"
17880 "function f() { g(); } \n"
17881 "function t(e) { throw e; } \n"
17884 "} catch (e1) { \n"
17887 " } catch (e2) { \n"
17891 v8::V8::AddMessageListener(RethrowStackTraceHandler);
17892 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17893 CompileRun(source);
17894 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17895 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler);
17899 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message,
17900 v8::Handle<v8::Value> data) {
17901 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17902 CHECK(!stack_trace.IsEmpty());
17903 int frame_count = stack_trace->GetFrameCount();
17904 CHECK_EQ(2, frame_count);
17905 int line_number[] = {3, 7};
17906 for (int i = 0; i < frame_count; i++) {
17907 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber());
17912 // Test that we do not recognize identity for primitive exceptions.
17913 TEST(RethrowPrimitiveStackTrace) {
17915 v8::HandleScope scope(env->GetIsolate());
17916 // We do not capture stack trace for non Error objects on creation time.
17917 // Instead, we capture the stack trace on last throw.
17918 const char* source =
17919 "function g() { throw 404; } \n"
17920 "function f() { g(); } \n"
17921 "function t(e) { throw e; } \n"
17924 "} catch (e1) { \n"
17927 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler);
17928 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17929 CompileRun(source);
17930 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17931 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler);
17935 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message,
17936 v8::Handle<v8::Value> data) {
17937 // Use the frame where JavaScript is called from.
17938 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17939 CHECK(!stack_trace.IsEmpty());
17940 CHECK_EQ(1, stack_trace->GetFrameCount());
17941 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber());
17945 // Test that the stack trace is captured when the error object is created and
17946 // not where it is thrown.
17947 TEST(RethrowExistingStackTrace) {
17949 v8::HandleScope scope(env->GetIsolate());
17950 const char* source =
17951 "var e = new Error(); \n"
17953 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler);
17954 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17955 CompileRun(source);
17956 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17957 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler);
17961 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message,
17962 v8::Handle<v8::Value> data) {
17963 // Use the frame where JavaScript is called from.
17964 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
17965 CHECK(!stack_trace.IsEmpty());
17966 CHECK_EQ(1, stack_trace->GetFrameCount());
17967 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber());
17971 // Test that the stack trace is captured where the bogus Error object is thrown.
17972 TEST(RethrowBogusErrorStackTrace) {
17974 v8::HandleScope scope(env->GetIsolate());
17975 const char* source =
17976 "var e = {__proto__: new Error()} \n"
17978 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler);
17979 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
17980 CompileRun(source);
17981 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
17982 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler);
17986 v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
17987 int promise_reject_counter = 0;
17988 int promise_revoke_counter = 0;
17989 int promise_reject_line_number = -1;
17990 int promise_reject_frame_count = -1;
17992 void PromiseRejectCallback(v8::PromiseRejectMessage message) {
17993 if (message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
17994 promise_reject_counter++;
17995 CcTest::global()->Set(v8_str("rejected"), message.GetPromise());
17996 CcTest::global()->Set(v8_str("value"), message.GetValue());
17997 v8::Handle<v8::StackTrace> stack_trace =
17998 v8::Exception::GetMessage(message.GetValue())->GetStackTrace();
17999 if (!stack_trace.IsEmpty()) {
18000 promise_reject_frame_count = stack_trace->GetFrameCount();
18001 if (promise_reject_frame_count > 0) {
18002 CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
18003 promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
18005 promise_reject_line_number = -1;
18009 promise_revoke_counter++;
18010 CcTest::global()->Set(v8_str("revoked"), message.GetPromise());
18011 CHECK(message.GetValue().IsEmpty());
18016 v8::Handle<v8::Promise> GetPromise(const char* name) {
18017 return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
18021 v8::Handle<v8::Value> RejectValue() {
18022 return CcTest::global()->Get(v8_str("value"));
18026 void ResetPromiseStates() {
18027 promise_reject_counter = 0;
18028 promise_revoke_counter = 0;
18029 promise_reject_line_number = -1;
18030 promise_reject_frame_count = -1;
18031 CcTest::global()->Set(v8_str("rejected"), v8_str(""));
18032 CcTest::global()->Set(v8_str("value"), v8_str(""));
18033 CcTest::global()->Set(v8_str("revoked"), v8_str(""));
18037 TEST(PromiseRejectCallback) {
18039 v8::Isolate* isolate = env->GetIsolate();
18040 v8::HandleScope scope(isolate);
18042 isolate->SetPromiseRejectCallback(PromiseRejectCallback);
18044 ResetPromiseStates();
18046 // Create promise p0.
18049 "var p0 = new Promise( \n"
18050 " function(res, rej) { \n"
18051 " reject = rej; \n"
18054 CHECK(!GetPromise("p0")->HasHandler());
18055 CHECK_EQ(0, promise_reject_counter);
18056 CHECK_EQ(0, promise_revoke_counter);
18058 // Add resolve handler (and default reject handler) to p0.
18059 CompileRun("var p1 = p0.then(function(){});");
18060 CHECK(GetPromise("p0")->HasHandler());
18061 CHECK(!GetPromise("p1")->HasHandler());
18062 CHECK_EQ(0, promise_reject_counter);
18063 CHECK_EQ(0, promise_revoke_counter);
18066 CompileRun("reject('ppp');");
18067 CHECK(GetPromise("p0")->HasHandler());
18068 CHECK(!GetPromise("p1")->HasHandler());
18069 CHECK_EQ(1, promise_reject_counter);
18070 CHECK_EQ(0, promise_revoke_counter);
18071 CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
18072 CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
18073 CHECK(RejectValue()->Equals(v8_str("ppp")));
18075 // Reject p0 again. Callback is not triggered again.
18076 CompileRun("reject();");
18077 CHECK(GetPromise("p0")->HasHandler());
18078 CHECK(!GetPromise("p1")->HasHandler());
18079 CHECK_EQ(1, promise_reject_counter);
18080 CHECK_EQ(0, promise_revoke_counter);
18082 // Add resolve handler to p1.
18083 CompileRun("var p2 = p1.then(function(){});");
18084 CHECK(GetPromise("p0")->HasHandler());
18085 CHECK(GetPromise("p1")->HasHandler());
18086 CHECK(!GetPromise("p2")->HasHandler());
18087 CHECK_EQ(2, promise_reject_counter);
18088 CHECK_EQ(1, promise_revoke_counter);
18089 CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
18090 CHECK(RejectValue()->Equals(v8_str("ppp")));
18091 CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
18093 ResetPromiseStates();
18095 // Create promise q0.
18097 "var q0 = new Promise( \n"
18098 " function(res, rej) { \n"
18099 " reject = rej; \n"
18102 CHECK(!GetPromise("q0")->HasHandler());
18103 CHECK_EQ(0, promise_reject_counter);
18104 CHECK_EQ(0, promise_revoke_counter);
18106 // Add reject handler to q0.
18107 CompileRun("var q1 = q0.catch(function() {});");
18108 CHECK(GetPromise("q0")->HasHandler());
18109 CHECK(!GetPromise("q1")->HasHandler());
18110 CHECK_EQ(0, promise_reject_counter);
18111 CHECK_EQ(0, promise_revoke_counter);
18114 CompileRun("reject('qq')");
18115 CHECK(GetPromise("q0")->HasHandler());
18116 CHECK(!GetPromise("q1")->HasHandler());
18117 CHECK_EQ(0, promise_reject_counter);
18118 CHECK_EQ(0, promise_revoke_counter);
18120 // Add a new reject handler, which rejects by returning Promise.reject().
18121 // The returned promise q_ triggers a reject callback at first, only to
18122 // revoke it when returning it causes q2 to be rejected.
18125 "var q2 = q0.catch( \n"
18127 " q_ = Promise.reject('qqq'); \n"
18131 CHECK(GetPromise("q0")->HasHandler());
18132 CHECK(!GetPromise("q1")->HasHandler());
18133 CHECK(!GetPromise("q2")->HasHandler());
18134 CHECK(GetPromise("q_")->HasHandler());
18135 CHECK_EQ(2, promise_reject_counter);
18136 CHECK_EQ(1, promise_revoke_counter);
18137 CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
18138 CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
18139 CHECK(RejectValue()->Equals(v8_str("qqq")));
18141 // Add a reject handler to the resolved q1, which rejects by throwing.
18143 "var q3 = q1.then( \n"
18145 " throw 'qqqq'; \n"
18148 CHECK(GetPromise("q0")->HasHandler());
18149 CHECK(GetPromise("q1")->HasHandler());
18150 CHECK(!GetPromise("q2")->HasHandler());
18151 CHECK(!GetPromise("q3")->HasHandler());
18152 CHECK_EQ(3, promise_reject_counter);
18153 CHECK_EQ(1, promise_revoke_counter);
18154 CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
18155 CHECK(RejectValue()->Equals(v8_str("qqqq")));
18157 ResetPromiseStates();
18159 // Create promise r0, which has three handlers, two of which handle rejects.
18161 "var r0 = new Promise( \n"
18162 " function(res, rej) { \n"
18163 " reject = rej; \n"
18166 "var r1 = r0.catch(function() {}); \n"
18167 "var r2 = r0.then(function() {}); \n"
18168 "var r3 = r0.then(function() {}, \n"
18169 " function() {}); \n");
18170 CHECK(GetPromise("r0")->HasHandler());
18171 CHECK(!GetPromise("r1")->HasHandler());
18172 CHECK(!GetPromise("r2")->HasHandler());
18173 CHECK(!GetPromise("r3")->HasHandler());
18174 CHECK_EQ(0, promise_reject_counter);
18175 CHECK_EQ(0, promise_revoke_counter);
18178 CompileRun("reject('rrr')");
18179 CHECK(GetPromise("r0")->HasHandler());
18180 CHECK(!GetPromise("r1")->HasHandler());
18181 CHECK(!GetPromise("r2")->HasHandler());
18182 CHECK(!GetPromise("r3")->HasHandler());
18183 CHECK_EQ(1, promise_reject_counter);
18184 CHECK_EQ(0, promise_revoke_counter);
18185 CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
18186 CHECK(RejectValue()->Equals(v8_str("rrr")));
18188 // Add reject handler to r2.
18189 CompileRun("var r4 = r2.catch(function() {});");
18190 CHECK(GetPromise("r0")->HasHandler());
18191 CHECK(!GetPromise("r1")->HasHandler());
18192 CHECK(GetPromise("r2")->HasHandler());
18193 CHECK(!GetPromise("r3")->HasHandler());
18194 CHECK(!GetPromise("r4")->HasHandler());
18195 CHECK_EQ(1, promise_reject_counter);
18196 CHECK_EQ(1, promise_revoke_counter);
18197 CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
18198 CHECK(RejectValue()->Equals(v8_str("rrr")));
18200 // Add reject handlers to r4.
18201 CompileRun("var r5 = r4.then(function() {}, function() {});");
18202 CHECK(GetPromise("r0")->HasHandler());
18203 CHECK(!GetPromise("r1")->HasHandler());
18204 CHECK(GetPromise("r2")->HasHandler());
18205 CHECK(!GetPromise("r3")->HasHandler());
18206 CHECK(GetPromise("r4")->HasHandler());
18207 CHECK(!GetPromise("r5")->HasHandler());
18208 CHECK_EQ(1, promise_reject_counter);
18209 CHECK_EQ(1, promise_revoke_counter);
18211 ResetPromiseStates();
18213 // Create promise s0, which has three handlers, none of which handle rejects.
18215 "var s0 = new Promise( \n"
18216 " function(res, rej) { \n"
18217 " reject = rej; \n"
18220 "var s1 = s0.then(function() {}); \n"
18221 "var s2 = s0.then(function() {}); \n"
18222 "var s3 = s0.then(function() {}); \n");
18223 CHECK(GetPromise("s0")->HasHandler());
18224 CHECK(!GetPromise("s1")->HasHandler());
18225 CHECK(!GetPromise("s2")->HasHandler());
18226 CHECK(!GetPromise("s3")->HasHandler());
18227 CHECK_EQ(0, promise_reject_counter);
18228 CHECK_EQ(0, promise_revoke_counter);
18231 CompileRun("reject('sss')");
18232 CHECK(GetPromise("s0")->HasHandler());
18233 CHECK(!GetPromise("s1")->HasHandler());
18234 CHECK(!GetPromise("s2")->HasHandler());
18235 CHECK(!GetPromise("s3")->HasHandler());
18236 CHECK_EQ(3, promise_reject_counter);
18237 CHECK_EQ(0, promise_revoke_counter);
18238 CHECK(RejectValue()->Equals(v8_str("sss")));
18240 // Test stack frames.
18241 V8::SetCaptureStackTraceForUncaughtExceptions(true);
18243 ResetPromiseStates();
18245 // Create promise t0, which is rejected in the constructor with an error.
18246 CompileRunWithOrigin(
18247 "var t0 = new Promise( \n"
18248 " function(res, rej) { \n"
18249 " reference_error; \n"
18253 CHECK(!GetPromise("t0")->HasHandler());
18254 CHECK_EQ(1, promise_reject_counter);
18255 CHECK_EQ(0, promise_revoke_counter);
18256 CHECK_EQ(2, promise_reject_frame_count);
18257 CHECK_EQ(3, promise_reject_line_number);
18259 ResetPromiseStates();
18261 // Create promise u0 and chain u1 to it, which is rejected via throw.
18262 CompileRunWithOrigin(
18263 "var u0 = Promise.resolve(); \n"
18264 "var u1 = u0.then( \n"
18266 " (function() { \n"
18267 " throw new Error(); \n"
18272 CHECK(GetPromise("u0")->HasHandler());
18273 CHECK(!GetPromise("u1")->HasHandler());
18274 CHECK_EQ(1, promise_reject_counter);
18275 CHECK_EQ(0, promise_revoke_counter);
18276 CHECK_EQ(2, promise_reject_frame_count);
18277 CHECK_EQ(5, promise_reject_line_number);
18279 // Throw in u3, which handles u1's rejection.
18280 CompileRunWithOrigin(
18281 "function f() { \n"
18282 " return (function() { \n"
18283 " return new Error(); \n"
18286 "var u2 = Promise.reject(f()); \n"
18287 "var u3 = u1.catch( \n"
18293 CHECK(GetPromise("u0")->HasHandler());
18294 CHECK(GetPromise("u1")->HasHandler());
18295 CHECK(GetPromise("u2")->HasHandler());
18296 CHECK(!GetPromise("u3")->HasHandler());
18297 CHECK_EQ(3, promise_reject_counter);
18298 CHECK_EQ(2, promise_revoke_counter);
18299 CHECK_EQ(3, promise_reject_frame_count);
18300 CHECK_EQ(3, promise_reject_line_number);
18302 ResetPromiseStates();
18304 // Create promise rejected promise v0, which is incorrectly handled by v1
18305 // via chaining cycle.
18306 CompileRunWithOrigin(
18307 "var v0 = Promise.reject(); \n"
18308 "var v1 = v0.catch( \n"
18314 CHECK(GetPromise("v0")->HasHandler());
18315 CHECK(!GetPromise("v1")->HasHandler());
18316 CHECK_EQ(2, promise_reject_counter);
18317 CHECK_EQ(1, promise_revoke_counter);
18318 CHECK_EQ(0, promise_reject_frame_count);
18319 CHECK_EQ(-1, promise_reject_line_number);
18323 void AnalyzeStackOfEvalWithSourceURL(
18324 const v8::FunctionCallbackInfo<v8::Value>& args) {
18325 v8::HandleScope scope(args.GetIsolate());
18326 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18327 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18328 CHECK_EQ(5, stackTrace->GetFrameCount());
18329 v8::Handle<v8::String> url = v8_str("eval_url");
18330 for (int i = 0; i < 3; i++) {
18331 v8::Handle<v8::String> name =
18332 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18333 CHECK(!name.IsEmpty());
18334 CHECK_EQ(url, name);
18339 TEST(SourceURLInStackTrace) {
18340 v8::Isolate* isolate = CcTest::isolate();
18341 v8::HandleScope scope(isolate);
18342 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18343 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"),
18344 v8::FunctionTemplate::New(isolate,
18345 AnalyzeStackOfEvalWithSourceURL));
18346 LocalContext context(0, templ);
18348 const char *source =
18349 "function outer() {\n"
18350 "function bar() {\n"
18351 " AnalyzeStackOfEvalWithSourceURL();\n"
18353 "function foo() {\n"
18359 "eval('(' + outer +')()%s');";
18361 i::ScopedVector<char> code(1024);
18362 i::SNPrintF(code, source, "//# sourceURL=eval_url");
18363 CHECK(CompileRun(code.start())->IsUndefined());
18364 i::SNPrintF(code, source, "//@ sourceURL=eval_url");
18365 CHECK(CompileRun(code.start())->IsUndefined());
18369 static int scriptIdInStack[2];
18371 void AnalyzeScriptIdInStack(
18372 const v8::FunctionCallbackInfo<v8::Value>& args) {
18373 v8::HandleScope scope(args.GetIsolate());
18374 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18375 args.GetIsolate(), 10, v8::StackTrace::kScriptId);
18376 CHECK_EQ(2, stackTrace->GetFrameCount());
18377 for (int i = 0; i < 2; i++) {
18378 scriptIdInStack[i] = stackTrace->GetFrame(i)->GetScriptId();
18383 TEST(ScriptIdInStackTrace) {
18384 v8::Isolate* isolate = CcTest::isolate();
18385 v8::HandleScope scope(isolate);
18386 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18387 templ->Set(v8_str("AnalyzeScriptIdInStack"),
18388 v8::FunctionTemplate::New(isolate, AnalyzeScriptIdInStack));
18389 LocalContext context(0, templ);
18391 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
18393 "function foo() {\n"
18394 " AnalyzeScriptIdInStack();"
18397 v8::Local<v8::Script> script = CompileWithOrigin(scriptSource, "test");
18399 for (int i = 0; i < 2; i++) {
18400 CHECK(scriptIdInStack[i] != v8::Message::kNoScriptIdInfo);
18401 CHECK_EQ(scriptIdInStack[i], script->GetUnboundScript()->GetId());
18406 void AnalyzeStackOfInlineScriptWithSourceURL(
18407 const v8::FunctionCallbackInfo<v8::Value>& args) {
18408 v8::HandleScope scope(args.GetIsolate());
18409 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18410 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18411 CHECK_EQ(4, stackTrace->GetFrameCount());
18412 v8::Handle<v8::String> url = v8_str("url");
18413 for (int i = 0; i < 3; i++) {
18414 v8::Handle<v8::String> name =
18415 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18416 CHECK(!name.IsEmpty());
18417 CHECK_EQ(url, name);
18422 TEST(InlineScriptWithSourceURLInStackTrace) {
18423 v8::Isolate* isolate = CcTest::isolate();
18424 v8::HandleScope scope(isolate);
18425 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18426 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"),
18427 v8::FunctionTemplate::New(
18428 CcTest::isolate(), AnalyzeStackOfInlineScriptWithSourceURL));
18429 LocalContext context(0, templ);
18431 const char *source =
18432 "function outer() {\n"
18433 "function bar() {\n"
18434 " AnalyzeStackOfInlineScriptWithSourceURL();\n"
18436 "function foo() {\n"
18444 i::ScopedVector<char> code(1024);
18445 i::SNPrintF(code, source, "//# sourceURL=source_url");
18446 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18447 i::SNPrintF(code, source, "//@ sourceURL=source_url");
18448 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined());
18452 void AnalyzeStackOfDynamicScriptWithSourceURL(
18453 const v8::FunctionCallbackInfo<v8::Value>& args) {
18454 v8::HandleScope scope(args.GetIsolate());
18455 v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(
18456 args.GetIsolate(), 10, v8::StackTrace::kDetailed);
18457 CHECK_EQ(4, stackTrace->GetFrameCount());
18458 v8::Handle<v8::String> url = v8_str("source_url");
18459 for (int i = 0; i < 3; i++) {
18460 v8::Handle<v8::String> name =
18461 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL();
18462 CHECK(!name.IsEmpty());
18463 CHECK_EQ(url, name);
18468 TEST(DynamicWithSourceURLInStackTrace) {
18469 v8::Isolate* isolate = CcTest::isolate();
18470 v8::HandleScope scope(isolate);
18471 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
18472 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"),
18473 v8::FunctionTemplate::New(
18474 CcTest::isolate(), AnalyzeStackOfDynamicScriptWithSourceURL));
18475 LocalContext context(0, templ);
18477 const char *source =
18478 "function outer() {\n"
18479 "function bar() {\n"
18480 " AnalyzeStackOfDynamicScriptWithSourceURL();\n"
18482 "function foo() {\n"
18490 i::ScopedVector<char> code(1024);
18491 i::SNPrintF(code, source, "//# sourceURL=source_url");
18492 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18493 i::SNPrintF(code, source, "//@ sourceURL=source_url");
18494 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined());
18498 TEST(DynamicWithSourceURLInStackTraceString) {
18499 LocalContext context;
18500 v8::HandleScope scope(context->GetIsolate());
18502 const char *source =
18503 "function outer() {\n"
18504 " function foo() {\n"
18511 i::ScopedVector<char> code(1024);
18512 i::SNPrintF(code, source, "//# sourceURL=source_url");
18513 v8::TryCatch try_catch;
18514 CompileRunWithOrigin(code.start(), "", 0, 0);
18515 CHECK(try_catch.HasCaught());
18516 v8::String::Utf8Value stack(try_catch.StackTrace());
18517 CHECK(strstr(*stack, "at foo (source_url:3:5)") != NULL);
18521 TEST(EvalWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18522 LocalContext context;
18523 v8::HandleScope scope(context->GetIsolate());
18525 const char *source =
18526 "function outer() {\n"
18527 " var scriptContents = \"function foo() { FAIL.FAIL; }\\\n"
18528 " //# sourceURL=source_url\";\n"
18529 " eval(scriptContents);\n"
18532 "//# sourceURL=outer_url";
18534 v8::TryCatch try_catch;
18535 CompileRun(source);
18536 CHECK(try_catch.HasCaught());
18538 Local<v8::Message> message = try_catch.Message();
18539 Handle<Value> sourceURL =
18540 message->GetScriptOrigin().ResourceName();
18541 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
18545 TEST(RecursionWithSourceURLInMessageScriptResourceNameOrSourceURL) {
18546 LocalContext context;
18547 v8::HandleScope scope(context->GetIsolate());
18549 const char *source =
18550 "function outer() {\n"
18551 " var scriptContents = \"function boo(){ boo(); }\\\n"
18552 " //# sourceURL=source_url\";\n"
18553 " eval(scriptContents);\n"
18556 "//# sourceURL=outer_url";
18558 v8::TryCatch try_catch;
18559 CompileRun(source);
18560 CHECK(try_catch.HasCaught());
18562 Local<v8::Message> message = try_catch.Message();
18563 Handle<Value> sourceURL =
18564 message->GetScriptOrigin().ResourceName();
18565 CHECK_EQ(*v8::String::Utf8Value(sourceURL), "source_url");
18569 static void CreateGarbageInOldSpace() {
18570 i::Factory* factory = CcTest::i_isolate()->factory();
18571 v8::HandleScope scope(CcTest::isolate());
18572 i::AlwaysAllocateScope always_allocate(CcTest::i_isolate());
18573 for (int i = 0; i < 1000; i++) {
18574 factory->NewFixedArray(1000, i::TENURED);
18579 // Test that idle notification can be handled and eventually returns true.
18580 TEST(IdleNotification) {
18581 const intptr_t MB = 1024 * 1024;
18582 const int IdlePauseInMs = 1000;
18584 v8::HandleScope scope(env->GetIsolate());
18585 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18586 CreateGarbageInOldSpace();
18587 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18588 CHECK_GT(size_with_garbage, initial_size + MB);
18589 bool finished = false;
18590 for (int i = 0; i < 200 && !finished; i++) {
18591 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18593 intptr_t final_size = CcTest::heap()->SizeOfObjects();
18595 CHECK_LT(final_size, initial_size + 1);
18599 // Test that idle notification can be handled and eventually collects garbage.
18600 TEST(IdleNotificationWithSmallHint) {
18601 const intptr_t MB = 1024 * 1024;
18602 const int IdlePauseInMs = 900;
18604 v8::HandleScope scope(env->GetIsolate());
18605 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18606 CreateGarbageInOldSpace();
18607 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18608 CHECK_GT(size_with_garbage, initial_size + MB);
18609 bool finished = false;
18610 for (int i = 0; i < 200 && !finished; i++) {
18611 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18613 intptr_t final_size = CcTest::heap()->SizeOfObjects();
18615 CHECK_LT(final_size, initial_size + 1);
18619 // Test that idle notification can be handled and eventually collects garbage.
18620 TEST(IdleNotificationWithLargeHint) {
18621 const intptr_t MB = 1024 * 1024;
18622 const int IdlePauseInMs = 900;
18624 v8::HandleScope scope(env->GetIsolate());
18625 intptr_t initial_size = CcTest::heap()->SizeOfObjects();
18626 CreateGarbageInOldSpace();
18627 intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
18628 CHECK_GT(size_with_garbage, initial_size + MB);
18629 bool finished = false;
18630 for (int i = 0; i < 200 && !finished; i++) {
18631 finished = env->GetIsolate()->IdleNotification(IdlePauseInMs);
18633 intptr_t final_size = CcTest::heap()->SizeOfObjects();
18635 CHECK_LT(final_size, initial_size + 1);
18639 TEST(Regress2333) {
18641 for (int i = 0; i < 3; i++) {
18642 CcTest::heap()->CollectGarbage(i::NEW_SPACE);
18646 static uint32_t* stack_limit;
18648 static void GetStackLimitCallback(
18649 const v8::FunctionCallbackInfo<v8::Value>& args) {
18650 stack_limit = reinterpret_cast<uint32_t*>(
18651 CcTest::i_isolate()->stack_guard()->real_climit());
18655 // Uses the address of a local variable to determine the stack top now.
18656 // Given a size, returns an address that is that far from the current
18658 static uint32_t* ComputeStackLimit(uint32_t size) {
18659 uint32_t* answer = &size - (size / sizeof(size));
18660 // If the size is very large and the stack is very near the bottom of
18661 // memory then the calculation above may wrap around and give an address
18662 // that is above the (downwards-growing) stack. In that case we return
18663 // a very low address.
18664 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size));
18669 // We need at least 165kB for an x64 debug build with clang and ASAN.
18670 static const int stack_breathing_room = 256 * i::KB;
18673 TEST(SetStackLimit) {
18674 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room);
18676 // Set stack limit.
18677 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18679 // Execute a script.
18681 v8::HandleScope scope(env->GetIsolate());
18682 Local<v8::FunctionTemplate> fun_templ =
18683 v8::FunctionTemplate::New(env->GetIsolate(), GetStackLimitCallback);
18684 Local<Function> fun = fun_templ->GetFunction();
18685 env->Global()->Set(v8_str("get_stack_limit"), fun);
18686 CompileRun("get_stack_limit();");
18688 CHECK(stack_limit == set_limit);
18692 TEST(SetStackLimitInThread) {
18693 uint32_t* set_limit;
18695 v8::Locker locker(CcTest::isolate());
18696 set_limit = ComputeStackLimit(stack_breathing_room);
18698 // Set stack limit.
18699 CcTest::isolate()->SetStackLimit(reinterpret_cast<uintptr_t>(set_limit));
18701 // Execute a script.
18702 v8::HandleScope scope(CcTest::isolate());
18704 Local<v8::FunctionTemplate> fun_templ =
18705 v8::FunctionTemplate::New(CcTest::isolate(), GetStackLimitCallback);
18706 Local<Function> fun = fun_templ->GetFunction();
18707 env->Global()->Set(v8_str("get_stack_limit"), fun);
18708 CompileRun("get_stack_limit();");
18710 CHECK(stack_limit == set_limit);
18713 v8::Locker locker(CcTest::isolate());
18714 CHECK(stack_limit == set_limit);
18719 THREADED_TEST(GetHeapStatistics) {
18721 v8::HandleScope scope(c1->GetIsolate());
18722 v8::HeapStatistics heap_statistics;
18723 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0);
18724 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0);
18725 c1->GetIsolate()->GetHeapStatistics(&heap_statistics);
18726 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0);
18727 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0);
18731 class VisitorImpl : public v8::ExternalResourceVisitor {
18733 explicit VisitorImpl(TestResource** resource) {
18734 for (int i = 0; i < 4; i++) {
18735 resource_[i] = resource[i];
18736 found_resource_[i] = false;
18739 virtual ~VisitorImpl() {}
18740 virtual void VisitExternalString(v8::Handle<v8::String> string) {
18741 if (!string->IsExternal()) {
18742 CHECK(string->IsExternalOneByte());
18745 v8::String::ExternalStringResource* resource =
18746 string->GetExternalStringResource();
18748 for (int i = 0; i < 4; i++) {
18749 if (resource_[i] == resource) {
18750 CHECK(!found_resource_[i]);
18751 found_resource_[i] = true;
18755 void CheckVisitedResources() {
18756 for (int i = 0; i < 4; i++) {
18757 CHECK(found_resource_[i]);
18762 v8::String::ExternalStringResource* resource_[4];
18763 bool found_resource_[4];
18767 TEST(ExternalizeOldSpaceTwoByteCons) {
18769 v8::HandleScope scope(env->GetIsolate());
18770 v8::Local<v8::String> cons =
18771 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18772 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18773 CcTest::heap()->CollectAllAvailableGarbage();
18774 CHECK(CcTest::heap()->old_pointer_space()->Contains(
18775 *v8::Utils::OpenHandle(*cons)));
18777 TestResource* resource = new TestResource(
18778 AsciiToTwoByteString("Romeo Montague Juliet Capulet"));
18779 cons->MakeExternal(resource);
18781 CHECK(cons->IsExternal());
18782 CHECK_EQ(resource, cons->GetExternalStringResource());
18783 String::Encoding encoding;
18784 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18785 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding);
18789 TEST(ExternalizeOldSpaceOneByteCons) {
18791 v8::HandleScope scope(env->GetIsolate());
18792 v8::Local<v8::String> cons =
18793 CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
18794 CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
18795 CcTest::heap()->CollectAllAvailableGarbage();
18796 CHECK(CcTest::heap()->old_pointer_space()->Contains(
18797 *v8::Utils::OpenHandle(*cons)));
18799 TestOneByteResource* resource =
18800 new TestOneByteResource(i::StrDup("Romeo Montague Juliet Capulet"));
18801 cons->MakeExternal(resource);
18803 CHECK(cons->IsExternalOneByte());
18804 CHECK_EQ(resource, cons->GetExternalOneByteStringResource());
18805 String::Encoding encoding;
18806 CHECK_EQ(resource, cons->GetExternalStringResourceBase(&encoding));
18807 CHECK_EQ(String::ONE_BYTE_ENCODING, encoding);
18811 TEST(VisitExternalStrings) {
18813 v8::HandleScope scope(env->GetIsolate());
18814 const char* string = "Some string";
18815 uint16_t* two_byte_string = AsciiToTwoByteString(string);
18816 TestResource* resource[4];
18817 resource[0] = new TestResource(two_byte_string);
18818 v8::Local<v8::String> string0 =
18819 v8::String::NewExternal(env->GetIsolate(), resource[0]);
18820 resource[1] = new TestResource(two_byte_string, NULL, false);
18821 v8::Local<v8::String> string1 =
18822 v8::String::NewExternal(env->GetIsolate(), resource[1]);
18824 // Externalized symbol.
18825 resource[2] = new TestResource(two_byte_string, NULL, false);
18826 v8::Local<v8::String> string2 = v8::String::NewFromUtf8(
18827 env->GetIsolate(), string, v8::String::kInternalizedString);
18828 CHECK(string2->MakeExternal(resource[2]));
18830 // Symbolized External.
18831 resource[3] = new TestResource(AsciiToTwoByteString("Some other string"));
18832 v8::Local<v8::String> string3 =
18833 v8::String::NewExternal(env->GetIsolate(), resource[3]);
18834 CcTest::heap()->CollectAllAvailableGarbage(); // Tenure string.
18835 // Turn into a symbol.
18836 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3);
18837 CHECK(!CcTest::i_isolate()->factory()->InternalizeString(
18838 string3_i).is_null());
18839 CHECK(string3_i->IsInternalizedString());
18841 // We need to add usages for string* to avoid warnings in GCC 4.7
18842 CHECK(string0->IsExternal());
18843 CHECK(string1->IsExternal());
18844 CHECK(string2->IsExternal());
18845 CHECK(string3->IsExternal());
18847 VisitorImpl visitor(resource);
18848 v8::V8::VisitExternalResources(&visitor);
18849 visitor.CheckVisitedResources();
18853 TEST(ExternalStringCollectedAtTearDown) {
18855 v8::Isolate* isolate = v8::Isolate::New();
18856 { v8::Isolate::Scope isolate_scope(isolate);
18857 v8::HandleScope handle_scope(isolate);
18858 const char* s = "One string to test them all, one string to find them.";
18859 TestOneByteResource* inscription =
18860 new TestOneByteResource(i::StrDup(s), &destroyed);
18861 v8::Local<v8::String> ring = v8::String::NewExternal(isolate, inscription);
18862 // Ring is still alive. Orcs are roaming freely across our lands.
18863 CHECK_EQ(0, destroyed);
18867 isolate->Dispose();
18868 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18869 CHECK_EQ(1, destroyed);
18873 TEST(ExternalInternalizedStringCollectedAtTearDown) {
18875 v8::Isolate* isolate = v8::Isolate::New();
18876 { v8::Isolate::Scope isolate_scope(isolate);
18877 LocalContext env(isolate);
18878 v8::HandleScope handle_scope(isolate);
18879 CompileRun("var ring = 'One string to test them all';");
18880 const char* s = "One string to test them all";
18881 TestOneByteResource* inscription =
18882 new TestOneByteResource(i::StrDup(s), &destroyed);
18883 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18884 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18885 ring->MakeExternal(inscription);
18886 // Ring is still alive. Orcs are roaming freely across our lands.
18887 CHECK_EQ(0, destroyed);
18891 isolate->Dispose();
18892 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18893 CHECK_EQ(1, destroyed);
18897 TEST(ExternalInternalizedStringCollectedAtGC) {
18899 { LocalContext env;
18900 v8::HandleScope handle_scope(env->GetIsolate());
18901 CompileRun("var ring = 'One string to test them all';");
18902 const char* s = "One string to test them all";
18903 TestOneByteResource* inscription =
18904 new TestOneByteResource(i::StrDup(s), &destroyed);
18905 v8::Local<v8::String> ring = CompileRun("ring")->ToString();
18906 CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
18907 ring->MakeExternal(inscription);
18908 // Ring is still alive. Orcs are roaming freely across our lands.
18909 CHECK_EQ(0, destroyed);
18913 // Garbage collector deals swift blows to evil.
18914 CcTest::i_isolate()->compilation_cache()->Clear();
18915 CcTest::heap()->CollectAllAvailableGarbage();
18917 // Ring has been destroyed. Free Peoples of Middle-earth Rejoice.
18918 CHECK_EQ(1, destroyed);
18922 static double DoubleFromBits(uint64_t value) {
18924 i::MemCopy(&target, &value, sizeof(target));
18929 static uint64_t DoubleToBits(double value) {
18931 i::MemCopy(&target, &value, sizeof(target));
18936 static double DoubleToDateTime(double input) {
18937 double date_limit = 864e13;
18938 if (std::isnan(input) || input < -date_limit || input > date_limit) {
18939 return v8::base::OS::nan_value();
18941 return (input < 0) ? -(std::floor(-input)) : std::floor(input);
18945 // We don't have a consistent way to write 64-bit constants syntactically, so we
18946 // split them into two 32-bit constants and combine them programmatically.
18947 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) {
18948 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits);
18952 THREADED_TEST(QuietSignalingNaNs) {
18953 LocalContext context;
18954 v8::Isolate* isolate = context->GetIsolate();
18955 v8::HandleScope scope(isolate);
18956 v8::TryCatch try_catch;
18958 // Special double values.
18959 double snan = DoubleFromBits(0x7ff00000, 0x00000001);
18960 double qnan = DoubleFromBits(0x7ff80000, 0x00000000);
18961 double infinity = DoubleFromBits(0x7ff00000, 0x00000000);
18962 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu);
18963 double min_normal = DoubleFromBits(0x00100000, 0x00000000);
18964 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu);
18965 double min_denormal = DoubleFromBits(0x00000000, 0x00000001);
18967 // Date values are capped at +/-100000000 days (times 864e5 ms per day)
18968 // on either side of the epoch.
18969 double date_limit = 864e13;
18971 double test_values[] = {
18993 int num_test_values = 20;
18995 for (int i = 0; i < num_test_values; i++) {
18996 double test_value = test_values[i];
18998 // Check that Number::New preserves non-NaNs and quiets SNaNs.
18999 v8::Handle<v8::Value> number = v8::Number::New(isolate, test_value);
19000 double stored_number = number->NumberValue();
19001 if (!std::isnan(test_value)) {
19002 CHECK_EQ(test_value, stored_number);
19004 uint64_t stored_bits = DoubleToBits(stored_number);
19005 // Check if quiet nan (bits 51..62 all set).
19006 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19007 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
19008 // Most significant fraction bit for quiet nan is set to 0
19009 // on MIPS architecture. Allowed by IEEE-754.
19010 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19012 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
19016 // Check that Date::New preserves non-NaNs in the date range and
19018 v8::Handle<v8::Value> date =
19019 v8::Date::New(isolate, test_value);
19020 double expected_stored_date = DoubleToDateTime(test_value);
19021 double stored_date = date->NumberValue();
19022 if (!std::isnan(expected_stored_date)) {
19023 CHECK_EQ(expected_stored_date, stored_date);
19025 uint64_t stored_bits = DoubleToBits(stored_date);
19026 // Check if quiet nan (bits 51..62 all set).
19027 #if (defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)) && \
19028 !defined(_MIPS_ARCH_MIPS64R6) && !defined(USE_SIMULATOR)
19029 // Most significant fraction bit for quiet nan is set to 0
19030 // on MIPS architecture. Allowed by IEEE-754.
19031 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff));
19033 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff));
19040 static void SpaghettiIncident(
19041 const v8::FunctionCallbackInfo<v8::Value>& args) {
19042 v8::HandleScope scope(args.GetIsolate());
19044 v8::Handle<v8::String> str(args[0]->ToString());
19046 if (tc.HasCaught())
19051 // Test that an exception can be propagated down through a spaghetti
19052 // stack using ReThrow.
19053 THREADED_TEST(SpaghettiStackReThrow) {
19054 v8::Isolate* isolate = CcTest::isolate();
19055 v8::HandleScope scope(isolate);
19056 LocalContext context;
19057 context->Global()->Set(
19058 v8::String::NewFromUtf8(isolate, "s"),
19059 v8::FunctionTemplate::New(isolate, SpaghettiIncident)->GetFunction());
19060 v8::TryCatch try_catch;
19064 " toString: function () {"
19074 CHECK(try_catch.HasCaught());
19075 v8::String::Utf8Value value(try_catch.Exception());
19076 CHECK_EQ(0, strcmp(*value, "Hey!"));
19081 v8::V8::Initialize();
19082 v8::Isolate* isolate = CcTest::isolate();
19083 v8::HandleScope scope(isolate);
19084 v8::Local<Context> other_context;
19087 // Create a context used to keep the code from aging in the compilation
19089 other_context = Context::New(isolate);
19091 // Context-dependent context data creates reference from the compilation
19092 // cache to the global object.
19093 const char* source_simple = "1";
19095 v8::HandleScope scope(isolate);
19096 v8::Local<Context> context = Context::New(isolate);
19099 Local<v8::String> obj = v8::String::NewFromUtf8(isolate, "");
19100 context->SetEmbedderData(0, obj);
19101 CompileRun(source_simple);
19104 isolate->ContextDisposedNotification();
19105 for (gc_count = 1; gc_count < 10; gc_count++) {
19106 other_context->Enter();
19107 CompileRun(source_simple);
19108 other_context->Exit();
19109 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19110 if (GetGlobalObjectsCount() == 1) break;
19112 CHECK_GE(2, gc_count);
19113 CHECK_EQ(1, GetGlobalObjectsCount());
19115 // Eval in a function creates reference from the compilation cache to the
19117 const char* source_eval = "function f(){eval('1')}; f()";
19119 v8::HandleScope scope(isolate);
19120 v8::Local<Context> context = Context::New(isolate);
19123 CompileRun(source_eval);
19126 isolate->ContextDisposedNotification();
19127 for (gc_count = 1; gc_count < 10; gc_count++) {
19128 other_context->Enter();
19129 CompileRun(source_eval);
19130 other_context->Exit();
19131 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19132 if (GetGlobalObjectsCount() == 1) break;
19134 CHECK_GE(2, gc_count);
19135 CHECK_EQ(1, GetGlobalObjectsCount());
19137 // Looking up the line number for an exception creates reference from the
19138 // compilation cache to the global object.
19139 const char* source_exception = "function f(){throw 1;} f()";
19141 v8::HandleScope scope(isolate);
19142 v8::Local<Context> context = Context::New(isolate);
19145 v8::TryCatch try_catch;
19146 CompileRun(source_exception);
19147 CHECK(try_catch.HasCaught());
19148 v8::Handle<v8::Message> message = try_catch.Message();
19149 CHECK(!message.IsEmpty());
19150 CHECK_EQ(1, message->GetLineNumber());
19153 isolate->ContextDisposedNotification();
19154 for (gc_count = 1; gc_count < 10; gc_count++) {
19155 other_context->Enter();
19156 CompileRun(source_exception);
19157 other_context->Exit();
19158 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19159 if (GetGlobalObjectsCount() == 1) break;
19161 CHECK_GE(2, gc_count);
19162 CHECK_EQ(1, GetGlobalObjectsCount());
19164 isolate->ContextDisposedNotification();
19168 THREADED_TEST(ScriptOrigin) {
19170 v8::HandleScope scope(env->GetIsolate());
19171 v8::ScriptOrigin origin =
19172 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19173 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19174 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
19175 v8::Script::Compile(script, &origin)->Run();
19176 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19177 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19178 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19179 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19181 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin();
19182 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName()));
19183 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value());
19185 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin();
19186 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName()));
19187 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value());
19191 THREADED_TEST(FunctionGetInferredName) {
19193 v8::HandleScope scope(env->GetIsolate());
19194 v8::ScriptOrigin origin =
19195 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19196 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19198 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;");
19199 v8::Script::Compile(script, &origin)->Run();
19200 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19201 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19202 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName()));
19206 THREADED_TEST(FunctionGetDisplayName) {
19208 v8::HandleScope scope(env->GetIsolate());
19209 const char* code = "var error = false;"
19210 "function a() { this.x = 1; };"
19211 "a.displayName = 'display_a';"
19212 "var b = (function() {"
19213 " var f = function() { this.x = 2; };"
19214 " f.displayName = 'display_b';"
19217 "var c = function() {};"
19218 "c.__defineGetter__('displayName', function() {"
19220 " throw new Error();"
19223 "d.__defineGetter__('displayName', function() {"
19225 " return 'wrong_display_name';"
19228 "e.displayName = 'wrong_display_name';"
19229 "e.__defineSetter__('displayName', function() {"
19231 " throw new Error();"
19234 "f.displayName = { 'foo': 6, toString: function() {"
19236 " return 'wrong_display_name';"
19238 "var g = function() {"
19239 " arguments.callee.displayName = 'set_in_runtime';"
19242 v8::ScriptOrigin origin =
19243 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19244 v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), code), &origin)
19246 v8::Local<v8::Value> error =
19247 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "error"));
19248 v8::Local<v8::Function> a = v8::Local<v8::Function>::Cast(
19249 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "a")));
19250 v8::Local<v8::Function> b = v8::Local<v8::Function>::Cast(
19251 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "b")));
19252 v8::Local<v8::Function> c = v8::Local<v8::Function>::Cast(
19253 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c")));
19254 v8::Local<v8::Function> d = v8::Local<v8::Function>::Cast(
19255 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "d")));
19256 v8::Local<v8::Function> e = v8::Local<v8::Function>::Cast(
19257 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "e")));
19258 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19259 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19260 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19261 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19262 CHECK_EQ(false, error->BooleanValue());
19263 CHECK_EQ("display_a", *v8::String::Utf8Value(a->GetDisplayName()));
19264 CHECK_EQ("display_b", *v8::String::Utf8Value(b->GetDisplayName()));
19265 CHECK(c->GetDisplayName()->IsUndefined());
19266 CHECK(d->GetDisplayName()->IsUndefined());
19267 CHECK(e->GetDisplayName()->IsUndefined());
19268 CHECK(f->GetDisplayName()->IsUndefined());
19269 CHECK_EQ("set_in_runtime", *v8::String::Utf8Value(g->GetDisplayName()));
19273 THREADED_TEST(ScriptLineNumber) {
19275 v8::HandleScope scope(env->GetIsolate());
19276 v8::ScriptOrigin origin =
19277 v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
19278 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19279 env->GetIsolate(), "function f() {}\n\nfunction g() {}");
19280 v8::Script::Compile(script, &origin)->Run();
19281 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19282 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19283 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19284 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19285 CHECK_EQ(0, f->GetScriptLineNumber());
19286 CHECK_EQ(2, g->GetScriptLineNumber());
19290 THREADED_TEST(ScriptColumnNumber) {
19292 v8::Isolate* isolate = env->GetIsolate();
19293 v8::HandleScope scope(isolate);
19294 v8::ScriptOrigin origin =
19295 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
19296 v8::Integer::New(isolate, 3),
19297 v8::Integer::New(isolate, 2));
19298 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19299 isolate, "function foo() {}\n\n function bar() {}");
19300 v8::Script::Compile(script, &origin)->Run();
19301 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19302 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
19303 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19304 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
19305 CHECK_EQ(14, foo->GetScriptColumnNumber());
19306 CHECK_EQ(17, bar->GetScriptColumnNumber());
19310 THREADED_TEST(FunctionIsBuiltin) {
19312 v8::Isolate* isolate = env->GetIsolate();
19313 v8::HandleScope scope(isolate);
19314 v8::Local<v8::Function> f;
19315 f = v8::Local<v8::Function>::Cast(CompileRun("Math.floor"));
19316 CHECK(f->IsBuiltin());
19317 f = v8::Local<v8::Function>::Cast(CompileRun("Object"));
19318 CHECK(f->IsBuiltin());
19319 f = v8::Local<v8::Function>::Cast(CompileRun("Object.__defineSetter__"));
19320 CHECK(f->IsBuiltin());
19321 f = v8::Local<v8::Function>::Cast(CompileRun("Array.prototype.toString"));
19322 CHECK(f->IsBuiltin());
19323 f = v8::Local<v8::Function>::Cast(CompileRun("function a() {}; a;"));
19324 CHECK(!f->IsBuiltin());
19328 THREADED_TEST(FunctionGetScriptId) {
19330 v8::Isolate* isolate = env->GetIsolate();
19331 v8::HandleScope scope(isolate);
19332 v8::ScriptOrigin origin =
19333 v8::ScriptOrigin(v8::String::NewFromUtf8(isolate, "test"),
19334 v8::Integer::New(isolate, 3),
19335 v8::Integer::New(isolate, 2));
19336 v8::Handle<v8::String> scriptSource = v8::String::NewFromUtf8(
19337 isolate, "function foo() {}\n\n function bar() {}");
19338 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin));
19340 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
19341 env->Global()->Get(v8::String::NewFromUtf8(isolate, "foo")));
19342 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
19343 env->Global()->Get(v8::String::NewFromUtf8(isolate, "bar")));
19344 CHECK_EQ(script->GetUnboundScript()->GetId(), foo->ScriptId());
19345 CHECK_EQ(script->GetUnboundScript()->GetId(), bar->ScriptId());
19349 THREADED_TEST(FunctionGetBoundFunction) {
19351 v8::HandleScope scope(env->GetIsolate());
19352 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::NewFromUtf8(
19353 env->GetIsolate(), "test"));
19354 v8::Handle<v8::String> script = v8::String::NewFromUtf8(
19356 "var a = new Object();\n"
19358 "function f () { return this.x };\n"
19359 "var g = f.bind(a);\n"
19361 v8::Script::Compile(script, &origin)->Run();
19362 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
19363 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
19364 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
19365 env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
19366 CHECK(g->GetBoundFunction()->IsFunction());
19367 Local<v8::Function> original_function = Local<v8::Function>::Cast(
19368 g->GetBoundFunction());
19369 CHECK_EQ(f->GetName(), original_function->GetName());
19370 CHECK_EQ(f->GetScriptLineNumber(), original_function->GetScriptLineNumber());
19371 CHECK_EQ(f->GetScriptColumnNumber(),
19372 original_function->GetScriptColumnNumber());
19376 static void GetterWhichReturns42(
19377 Local<String> name,
19378 const v8::PropertyCallbackInfo<v8::Value>& info) {
19379 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19380 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19381 info.GetReturnValue().Set(v8_num(42));
19385 static void SetterWhichSetsYOnThisTo23(
19386 Local<String> name,
19387 Local<Value> value,
19388 const v8::PropertyCallbackInfo<void>& info) {
19389 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19390 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19391 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19395 void FooGetInterceptor(Local<String> name,
19396 const v8::PropertyCallbackInfo<v8::Value>& info) {
19397 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19398 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19399 if (!name->Equals(v8_str("foo"))) return;
19400 info.GetReturnValue().Set(v8_num(42));
19404 void FooSetInterceptor(Local<String> name,
19405 Local<Value> value,
19406 const v8::PropertyCallbackInfo<v8::Value>& info) {
19407 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
19408 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
19409 if (!name->Equals(v8_str("foo"))) return;
19410 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19411 info.GetReturnValue().Set(v8_num(23));
19415 TEST(SetterOnConstructorPrototype) {
19416 v8::Isolate* isolate = CcTest::isolate();
19417 v8::HandleScope scope(isolate);
19418 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19419 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19420 SetterWhichSetsYOnThisTo23);
19421 LocalContext context;
19422 context->Global()->Set(v8_str("P"), templ->NewInstance());
19423 CompileRun("function C1() {"
19426 "C1.prototype = P;"
19430 "C2.prototype = { };"
19431 "C2.prototype.__proto__ = P;");
19433 v8::Local<v8::Script> script;
19434 script = v8_compile("new C1();");
19435 for (int i = 0; i < 10; i++) {
19436 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19437 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
19438 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
19441 script = v8_compile("new C2();");
19442 for (int i = 0; i < 10; i++) {
19443 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
19444 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value());
19445 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value());
19450 static void NamedPropertyGetterWhichReturns42(
19451 Local<String> name,
19452 const v8::PropertyCallbackInfo<v8::Value>& info) {
19453 info.GetReturnValue().Set(v8_num(42));
19457 static void NamedPropertySetterWhichSetsYOnThisTo23(
19458 Local<String> name,
19459 Local<Value> value,
19460 const v8::PropertyCallbackInfo<v8::Value>& info) {
19461 if (name->Equals(v8_str("x"))) {
19462 Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
19467 THREADED_TEST(InterceptorOnConstructorPrototype) {
19468 v8::Isolate* isolate = CcTest::isolate();
19469 v8::HandleScope scope(isolate);
19470 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19471 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
19472 NamedPropertySetterWhichSetsYOnThisTo23);
19473 LocalContext context;
19474 context->Global()->Set(v8_str("P"), templ->NewInstance());
19475 CompileRun("function C1() {"
19478 "C1.prototype = P;"
19482 "C2.prototype = { };"
19483 "C2.prototype.__proto__ = P;");
19485 v8::Local<v8::Script> script;
19486 script = v8_compile("new C1();");
19487 for (int i = 0; i < 10; i++) {
19488 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19489 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
19490 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
19493 script = v8_compile("new C2();");
19494 for (int i = 0; i < 10; i++) {
19495 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run());
19496 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value());
19497 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value());
19503 const char* source = "function C1() {"
19506 "C1.prototype = P;";
19508 LocalContext context;
19509 v8::Isolate* isolate = context->GetIsolate();
19510 v8::HandleScope scope(isolate);
19511 v8::Local<v8::Script> script;
19513 // Use a simple object as prototype.
19514 v8::Local<v8::Object> prototype = v8::Object::New(isolate);
19515 prototype->Set(v8_str("y"), v8_num(42));
19516 context->Global()->Set(v8_str("P"), prototype);
19518 // This compile will add the code to the compilation cache.
19519 CompileRun(source);
19521 script = v8_compile("new C1();");
19522 // Allow enough iterations for the inobject slack tracking logic
19523 // to finalize instance size and install the fast construct stub.
19524 for (int i = 0; i < 256; i++) {
19525 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19526 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value());
19527 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value());
19530 // Use an API object with accessors as prototype.
19531 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
19532 templ->SetAccessor(v8_str("x"), GetterWhichReturns42,
19533 SetterWhichSetsYOnThisTo23);
19534 context->Global()->Set(v8_str("P"), templ->NewInstance());
19536 // This compile will get the code from the compilation cache.
19537 CompileRun(source);
19539 script = v8_compile("new C1();");
19540 for (int i = 0; i < 10; i++) {
19541 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run());
19542 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value());
19543 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
19547 v8::Isolate* gc_callbacks_isolate = NULL;
19548 int prologue_call_count = 0;
19549 int epilogue_call_count = 0;
19550 int prologue_call_count_second = 0;
19551 int epilogue_call_count_second = 0;
19552 int prologue_call_count_alloc = 0;
19553 int epilogue_call_count_alloc = 0;
19555 void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
19556 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19557 ++prologue_call_count;
19561 void PrologueCallback(v8::Isolate* isolate,
19563 v8::GCCallbackFlags flags) {
19564 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19565 CHECK_EQ(gc_callbacks_isolate, isolate);
19566 ++prologue_call_count;
19570 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
19571 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19572 ++epilogue_call_count;
19576 void EpilogueCallback(v8::Isolate* isolate,
19578 v8::GCCallbackFlags flags) {
19579 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19580 CHECK_EQ(gc_callbacks_isolate, isolate);
19581 ++epilogue_call_count;
19585 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
19586 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19587 ++prologue_call_count_second;
19591 void PrologueCallbackSecond(v8::Isolate* isolate,
19593 v8::GCCallbackFlags flags) {
19594 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19595 CHECK_EQ(gc_callbacks_isolate, isolate);
19596 ++prologue_call_count_second;
19600 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
19601 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19602 ++epilogue_call_count_second;
19606 void EpilogueCallbackSecond(v8::Isolate* isolate,
19608 v8::GCCallbackFlags flags) {
19609 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19610 CHECK_EQ(gc_callbacks_isolate, isolate);
19611 ++epilogue_call_count_second;
19615 void PrologueCallbackAlloc(v8::Isolate* isolate,
19617 v8::GCCallbackFlags flags) {
19618 v8::HandleScope scope(isolate);
19620 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19621 CHECK_EQ(gc_callbacks_isolate, isolate);
19622 ++prologue_call_count_alloc;
19624 // Simulate full heap to see if we will reenter this callback
19625 SimulateFullSpace(CcTest::heap()->new_space());
19627 Local<Object> obj = Object::New(isolate);
19628 CHECK(!obj.IsEmpty());
19630 CcTest::heap()->CollectAllGarbage(
19631 i::Heap::kAbortIncrementalMarkingMask);
19635 void EpilogueCallbackAlloc(v8::Isolate* isolate,
19637 v8::GCCallbackFlags flags) {
19638 v8::HandleScope scope(isolate);
19640 CHECK_EQ(flags, v8::kNoGCCallbackFlags);
19641 CHECK_EQ(gc_callbacks_isolate, isolate);
19642 ++epilogue_call_count_alloc;
19644 // Simulate full heap to see if we will reenter this callback
19645 SimulateFullSpace(CcTest::heap()->new_space());
19647 Local<Object> obj = Object::New(isolate);
19648 CHECK(!obj.IsEmpty());
19650 CcTest::heap()->CollectAllGarbage(
19651 i::Heap::kAbortIncrementalMarkingMask);
19655 TEST(GCCallbacksOld) {
19656 LocalContext context;
19658 v8::V8::AddGCPrologueCallback(PrologueCallback);
19659 v8::V8::AddGCEpilogueCallback(EpilogueCallback);
19660 CHECK_EQ(0, prologue_call_count);
19661 CHECK_EQ(0, epilogue_call_count);
19662 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19663 CHECK_EQ(1, prologue_call_count);
19664 CHECK_EQ(1, epilogue_call_count);
19665 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
19666 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
19667 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19668 CHECK_EQ(2, prologue_call_count);
19669 CHECK_EQ(2, epilogue_call_count);
19670 CHECK_EQ(1, prologue_call_count_second);
19671 CHECK_EQ(1, epilogue_call_count_second);
19672 v8::V8::RemoveGCPrologueCallback(PrologueCallback);
19673 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
19674 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19675 CHECK_EQ(2, prologue_call_count);
19676 CHECK_EQ(2, epilogue_call_count);
19677 CHECK_EQ(2, prologue_call_count_second);
19678 CHECK_EQ(2, epilogue_call_count_second);
19679 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
19680 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19681 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19682 CHECK_EQ(2, prologue_call_count);
19683 CHECK_EQ(2, epilogue_call_count);
19684 CHECK_EQ(2, prologue_call_count_second);
19685 CHECK_EQ(2, epilogue_call_count_second);
19689 TEST(GCCallbacks) {
19690 LocalContext context;
19691 v8::Isolate* isolate = context->GetIsolate();
19692 gc_callbacks_isolate = isolate;
19693 isolate->AddGCPrologueCallback(PrologueCallback);
19694 isolate->AddGCEpilogueCallback(EpilogueCallback);
19695 CHECK_EQ(0, prologue_call_count);
19696 CHECK_EQ(0, epilogue_call_count);
19697 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19698 CHECK_EQ(1, prologue_call_count);
19699 CHECK_EQ(1, epilogue_call_count);
19700 isolate->AddGCPrologueCallback(PrologueCallbackSecond);
19701 isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
19702 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19703 CHECK_EQ(2, prologue_call_count);
19704 CHECK_EQ(2, epilogue_call_count);
19705 CHECK_EQ(1, prologue_call_count_second);
19706 CHECK_EQ(1, epilogue_call_count_second);
19707 isolate->RemoveGCPrologueCallback(PrologueCallback);
19708 isolate->RemoveGCEpilogueCallback(EpilogueCallback);
19709 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19710 CHECK_EQ(2, prologue_call_count);
19711 CHECK_EQ(2, epilogue_call_count);
19712 CHECK_EQ(2, prologue_call_count_second);
19713 CHECK_EQ(2, epilogue_call_count_second);
19714 isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
19715 isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
19716 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
19717 CHECK_EQ(2, prologue_call_count);
19718 CHECK_EQ(2, epilogue_call_count);
19719 CHECK_EQ(2, prologue_call_count_second);
19720 CHECK_EQ(2, epilogue_call_count_second);
19722 CHECK_EQ(0, prologue_call_count_alloc);
19723 CHECK_EQ(0, epilogue_call_count_alloc);
19724 isolate->AddGCPrologueCallback(PrologueCallbackAlloc);
19725 isolate->AddGCEpilogueCallback(EpilogueCallbackAlloc);
19726 CcTest::heap()->CollectAllGarbage(
19727 i::Heap::kAbortIncrementalMarkingMask);
19728 CHECK_EQ(1, prologue_call_count_alloc);
19729 CHECK_EQ(1, epilogue_call_count_alloc);
19730 isolate->RemoveGCPrologueCallback(PrologueCallbackAlloc);
19731 isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
19735 THREADED_TEST(AddToJSFunctionResultCache) {
19736 i::FLAG_stress_compaction = false;
19737 i::FLAG_allow_natives_syntax = true;
19738 v8::HandleScope scope(CcTest::isolate());
19740 LocalContext context;
19746 " var r0 = %_GetFromCache(0, key0);"
19747 " var r1 = %_GetFromCache(0, key1);"
19748 " var r0_ = %_GetFromCache(0, key0);"
19750 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;"
19751 " var r1_ = %_GetFromCache(0, key1);"
19753 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;"
19754 " return 'PASSED';"
19756 CcTest::heap()->ClearJSFunctionResultCaches();
19757 ExpectString(code, "PASSED");
19761 THREADED_TEST(FillJSFunctionResultCache) {
19762 i::FLAG_allow_natives_syntax = true;
19763 LocalContext context;
19764 v8::HandleScope scope(context->GetIsolate());
19769 " var r = %_GetFromCache(0, k);"
19770 " for (var i = 0; i < 16; i++) {"
19771 " %_GetFromCache(0, 'a' + i);"
19773 " if (r === %_GetFromCache(0, k))"
19774 " return 'FAILED: k0CacheSize is too small';"
19775 " return 'PASSED';"
19777 CcTest::heap()->ClearJSFunctionResultCaches();
19778 ExpectString(code, "PASSED");
19782 THREADED_TEST(RoundRobinGetFromCache) {
19783 i::FLAG_allow_natives_syntax = true;
19784 LocalContext context;
19785 v8::HandleScope scope(context->GetIsolate());
19790 " for (var i = 0; i < 16; i++) keys.push(i);"
19791 " var values = [];"
19792 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19793 " for (var i = 0; i < 16; i++) {"
19794 " var v = %_GetFromCache(0, keys[i]);"
19795 " if (v.toString() !== values[i].toString())"
19796 " return 'Wrong value for ' + "
19797 " keys[i] + ': ' + v + ' vs. ' + values[i];"
19799 " return 'PASSED';"
19801 CcTest::heap()->ClearJSFunctionResultCaches();
19802 ExpectString(code, "PASSED");
19806 THREADED_TEST(ReverseGetFromCache) {
19807 i::FLAG_allow_natives_syntax = true;
19808 LocalContext context;
19809 v8::HandleScope scope(context->GetIsolate());
19814 " for (var i = 0; i < 16; i++) keys.push(i);"
19815 " var values = [];"
19816 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);"
19817 " for (var i = 15; i >= 16; i--) {"
19818 " var v = %_GetFromCache(0, keys[i]);"
19819 " if (v !== values[i])"
19820 " return 'Wrong value for ' + "
19821 " keys[i] + ': ' + v + ' vs. ' + values[i];"
19823 " return 'PASSED';"
19825 CcTest::heap()->ClearJSFunctionResultCaches();
19826 ExpectString(code, "PASSED");
19830 THREADED_TEST(TestEviction) {
19831 i::FLAG_allow_natives_syntax = true;
19832 LocalContext context;
19833 v8::HandleScope scope(context->GetIsolate());
19837 " for (var i = 0; i < 2*16; i++) {"
19838 " %_GetFromCache(0, 'a' + i);"
19840 " return 'PASSED';"
19842 CcTest::heap()->ClearJSFunctionResultCaches();
19843 ExpectString(code, "PASSED");
19847 THREADED_TEST(TwoByteStringInOneByteCons) {
19848 // See Chromium issue 47824.
19849 LocalContext context;
19850 v8::HandleScope scope(context->GetIsolate());
19852 const char* init_code =
19853 "var str1 = 'abelspendabel';"
19854 "var str2 = str1 + str1 + str1;"
19856 Local<Value> result = CompileRun(init_code);
19858 Local<Value> indexof = CompileRun("str2.indexOf('els')");
19859 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
19861 CHECK(result->IsString());
19862 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
19863 int length = string->length();
19864 CHECK(string->IsOneByteRepresentation());
19866 i::Handle<i::String> flat_string = i::String::Flatten(string);
19868 CHECK(string->IsOneByteRepresentation());
19869 CHECK(flat_string->IsOneByteRepresentation());
19871 // Create external resource.
19872 uint16_t* uc16_buffer = new uint16_t[length + 1];
19874 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length);
19875 uc16_buffer[length] = 0;
19877 TestResource resource(uc16_buffer);
19879 flat_string->MakeExternal(&resource);
19881 CHECK(flat_string->IsTwoByteRepresentation());
19883 // If the cons string has been short-circuited, skip the following checks.
19884 if (!string.is_identical_to(flat_string)) {
19885 // At this point, we should have a Cons string which is flat and one-byte,
19886 // with a first half that is a two-byte string (although it only contains
19887 // one-byte characters). This is a valid sequence of steps, and it can
19888 // happen in real pages.
19889 CHECK(string->IsOneByteRepresentation());
19890 i::ConsString* cons = i::ConsString::cast(*string);
19891 CHECK_EQ(0, cons->second()->length());
19892 CHECK(cons->first()->IsTwoByteRepresentation());
19895 // Check that some string operations work.
19898 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
19899 CHECK_EQ(6, reresult->Int32Value());
19902 reresult = CompileRun("str2.match(/abe./g).length;");
19903 CHECK_EQ(6, reresult->Int32Value());
19905 reresult = CompileRun("str2.search(/bel/g);");
19906 CHECK_EQ(1, reresult->Int32Value());
19908 reresult = CompileRun("str2.search(/be./g);");
19909 CHECK_EQ(1, reresult->Int32Value());
19911 ExpectTrue("/bel/g.test(str2);");
19913 ExpectTrue("/be./g.test(str2);");
19915 reresult = CompileRun("/bel/g.exec(str2);");
19916 CHECK(!reresult->IsNull());
19918 reresult = CompileRun("/be./g.exec(str2);");
19919 CHECK(!reresult->IsNull());
19921 ExpectString("str2.substring(2, 10);", "elspenda");
19923 ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
19925 ExpectString("str2.charAt(2);", "e");
19927 ExpectObject("str2.indexOf('els');", indexof);
19929 ExpectObject("str2.lastIndexOf('dab');", lastindexof);
19931 reresult = CompileRun("str2.charCodeAt(2);");
19932 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value());
19936 TEST(ContainsOnlyOneByte) {
19937 v8::V8::Initialize();
19938 v8::Isolate* isolate = CcTest::isolate();
19939 v8::HandleScope scope(isolate);
19940 // Make a buffer long enough that it won't automatically be converted.
19941 const int length = 512;
19942 // Ensure word aligned assignment.
19943 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t);
19944 i::SmartArrayPointer<uintptr_t>
19945 aligned_contents(new uintptr_t[aligned_length]);
19946 uint16_t* string_contents =
19947 reinterpret_cast<uint16_t*>(aligned_contents.get());
19948 // Set to contain only one byte.
19949 for (int i = 0; i < length-1; i++) {
19950 string_contents[i] = 0x41;
19952 string_contents[length-1] = 0;
19954 Handle<String> string =
19955 String::NewExternal(isolate,
19956 new TestResource(string_contents, NULL, false));
19957 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19958 // Counter example.
19959 string = String::NewFromTwoByte(isolate, string_contents);
19960 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19961 // Test left right and balanced cons strings.
19962 Handle<String> base = String::NewFromUtf8(isolate, "a");
19963 Handle<String> left = base;
19964 Handle<String> right = base;
19965 for (int i = 0; i < 1000; i++) {
19966 left = String::Concat(base, left);
19967 right = String::Concat(right, base);
19969 Handle<String> balanced = String::Concat(left, base);
19970 balanced = String::Concat(balanced, right);
19971 Handle<String> cons_strings[] = {left, balanced, right};
19972 Handle<String> two_byte =
19973 String::NewExternal(isolate,
19974 new TestResource(string_contents, NULL, false));
19975 USE(two_byte); USE(cons_strings);
19976 for (size_t i = 0; i < arraysize(cons_strings); i++) {
19977 // Base assumptions.
19978 string = cons_strings[i];
19979 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte());
19980 // Test left and right concatentation.
19981 string = String::Concat(two_byte, cons_strings[i]);
19982 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19983 string = String::Concat(cons_strings[i], two_byte);
19984 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte());
19986 // Set bits in different positions
19987 // for strings of different lengths and alignments.
19988 for (int alignment = 0; alignment < 7; alignment++) {
19989 for (int size = 2; alignment + size < length; size *= 2) {
19990 int zero_offset = size + alignment;
19991 string_contents[zero_offset] = 0;
19992 for (int i = 0; i < size; i++) {
19993 int shift = 8 + (i % 7);
19994 string_contents[alignment + i] = 1 << shift;
19995 string = String::NewExternal(
19997 new TestResource(string_contents + alignment, NULL, false));
19998 CHECK_EQ(size, string->Length());
19999 CHECK(!string->ContainsOnlyOneByte());
20000 string_contents[alignment + i] = 0x41;
20002 string_contents[zero_offset] = 0x41;
20008 // Failed access check callback that performs a GC on each invocation.
20009 void FailedAccessCheckCallbackGC(Local<v8::Object> target,
20010 v8::AccessType type,
20011 Local<v8::Value> data) {
20012 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20016 TEST(GCInFailedAccessCheckCallback) {
20017 // Install a failed access check callback that performs a GC on each
20018 // invocation. Then force the callback to be called from va
20020 v8::V8::Initialize();
20021 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC);
20023 v8::Isolate* isolate = CcTest::isolate();
20024 v8::HandleScope scope(isolate);
20026 // Create an ObjectTemplate for global objects and install access
20027 // check callbacks that will block access.
20028 v8::Handle<v8::ObjectTemplate> global_template =
20029 v8::ObjectTemplate::New(isolate);
20030 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker,
20031 IndexedGetAccessBlocker,
20032 v8::Handle<v8::Value>(),
20035 // Create a context and set an x property on it's global object.
20036 LocalContext context0(NULL, global_template);
20037 context0->Global()->Set(v8_str("x"), v8_num(42));
20038 v8::Handle<v8::Object> global0 = context0->Global();
20040 // Create a context with a different security token so that the
20041 // failed access check callback will be called on each access.
20042 LocalContext context1(NULL, global_template);
20043 context1->Global()->Set(v8_str("other"), global0);
20045 // Get property with failed access check.
20046 ExpectUndefined("other.x");
20048 // Get element with failed access check.
20049 ExpectUndefined("other[0]");
20051 // Set property with failed access check.
20052 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()");
20053 CHECK(result->IsObject());
20055 // Set element with failed access check.
20056 result = CompileRun("other[0] = new Object()");
20057 CHECK(result->IsObject());
20059 // Get property attribute with failed access check.
20060 ExpectFalse("\'x\' in other");
20062 // Get property attribute for element with failed access check.
20063 ExpectFalse("0 in other");
20065 // Delete property.
20066 ExpectFalse("delete other.x");
20069 CHECK_EQ(false, global0->Delete(0));
20073 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x")));
20075 // Define JavaScript accessor.
20076 ExpectUndefined("Object.prototype.__defineGetter__.call("
20077 " other, \'x\', function() { return 42; })");
20080 ExpectUndefined("Object.prototype.__lookupGetter__.call("
20084 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')");
20086 CHECK_EQ(false, global0->HasRealIndexedProperty(0));
20087 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x")));
20088 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x")));
20090 // Reset the failed access check callback so it does not influence
20091 // the other tests.
20092 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
20096 TEST(IsolateNewDispose) {
20097 v8::Isolate* current_isolate = CcTest::isolate();
20098 v8::Isolate* isolate = v8::Isolate::New();
20099 CHECK(isolate != NULL);
20100 CHECK(current_isolate != isolate);
20101 CHECK(current_isolate == CcTest::isolate());
20103 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20104 last_location = last_message = NULL;
20105 isolate->Dispose();
20106 CHECK_EQ(last_location, NULL);
20107 CHECK_EQ(last_message, NULL);
20111 UNINITIALIZED_TEST(DisposeIsolateWhenInUse) {
20112 v8::Isolate* isolate = v8::Isolate::New();
20114 v8::Isolate::Scope i_scope(isolate);
20115 v8::HandleScope scope(isolate);
20116 LocalContext context(isolate);
20117 // Run something in this isolate.
20118 ExpectTrue("true");
20119 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20120 last_location = last_message = NULL;
20121 // Still entered, should fail.
20122 isolate->Dispose();
20123 CHECK_NE(last_location, NULL);
20124 CHECK_NE(last_message, NULL);
20126 isolate->Dispose();
20130 TEST(RunTwoIsolatesOnSingleThread) {
20132 v8::Isolate* isolate1 = v8::Isolate::New();
20134 v8::Persistent<v8::Context> context1;
20136 v8::HandleScope scope(isolate1);
20137 context1.Reset(isolate1, Context::New(isolate1));
20141 v8::HandleScope scope(isolate1);
20142 v8::Local<v8::Context> context =
20143 v8::Local<v8::Context>::New(isolate1, context1);
20144 v8::Context::Scope context_scope(context);
20145 // Run something in new isolate.
20146 CompileRun("var foo = 'isolate 1';");
20147 ExpectString("function f() { return foo; }; f()", "isolate 1");
20151 v8::Isolate* isolate2 = v8::Isolate::New();
20152 v8::Persistent<v8::Context> context2;
20155 v8::Isolate::Scope iscope(isolate2);
20156 v8::HandleScope scope(isolate2);
20157 context2.Reset(isolate2, Context::New(isolate2));
20158 v8::Local<v8::Context> context =
20159 v8::Local<v8::Context>::New(isolate2, context2);
20160 v8::Context::Scope context_scope(context);
20162 // Run something in new isolate.
20163 CompileRun("var foo = 'isolate 2';");
20164 ExpectString("function f() { return foo; }; f()", "isolate 2");
20168 v8::HandleScope scope(isolate1);
20169 v8::Local<v8::Context> context =
20170 v8::Local<v8::Context>::New(isolate1, context1);
20171 v8::Context::Scope context_scope(context);
20172 // Now again in isolate 1
20173 ExpectString("function f() { return foo; }; f()", "isolate 1");
20178 // Run some stuff in default isolate.
20179 v8::Persistent<v8::Context> context_default;
20181 v8::Isolate* isolate = CcTest::isolate();
20182 v8::Isolate::Scope iscope(isolate);
20183 v8::HandleScope scope(isolate);
20184 context_default.Reset(isolate, Context::New(isolate));
20188 v8::HandleScope scope(CcTest::isolate());
20189 v8::Local<v8::Context> context =
20190 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20191 v8::Context::Scope context_scope(context);
20192 // Variables in other isolates should be not available, verify there
20193 // is an exception.
20194 ExpectTrue("function f() {"
20202 "var isDefaultIsolate = true;"
20209 v8::Isolate::Scope iscope(isolate2);
20210 v8::HandleScope scope(isolate2);
20211 v8::Local<v8::Context> context =
20212 v8::Local<v8::Context>::New(isolate2, context2);
20213 v8::Context::Scope context_scope(context);
20214 ExpectString("function f() { return foo; }; f()", "isolate 2");
20218 v8::HandleScope scope(v8::Isolate::GetCurrent());
20219 v8::Local<v8::Context> context =
20220 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1);
20221 v8::Context::Scope context_scope(context);
20222 ExpectString("function f() { return foo; }; f()", "isolate 1");
20226 v8::Isolate::Scope iscope(isolate2);
20233 v8::V8::SetFatalErrorHandler(StoringErrorCallback);
20234 last_location = last_message = NULL;
20236 isolate1->Dispose();
20237 CHECK_EQ(last_location, NULL);
20238 CHECK_EQ(last_message, NULL);
20240 isolate2->Dispose();
20241 CHECK_EQ(last_location, NULL);
20242 CHECK_EQ(last_message, NULL);
20244 // Check that default isolate still runs.
20246 v8::HandleScope scope(CcTest::isolate());
20247 v8::Local<v8::Context> context =
20248 v8::Local<v8::Context>::New(CcTest::isolate(), context_default);
20249 v8::Context::Scope context_scope(context);
20250 ExpectTrue("function f() { return isDefaultIsolate; }; f()");
20255 static int CalcFibonacci(v8::Isolate* isolate, int limit) {
20256 v8::Isolate::Scope isolate_scope(isolate);
20257 v8::HandleScope scope(isolate);
20258 LocalContext context(isolate);
20259 i::ScopedVector<char> code(1024);
20260 i::SNPrintF(code, "function fib(n) {"
20261 " if (n <= 2) return 1;"
20262 " return fib(n-1) + fib(n-2);"
20265 Local<Value> value = CompileRun(code.start());
20266 CHECK(value->IsNumber());
20267 return static_cast<int>(value->NumberValue());
20270 class IsolateThread : public v8::base::Thread {
20272 explicit IsolateThread(int fib_limit)
20273 : Thread(Options("IsolateThread")), fib_limit_(fib_limit), result_(0) {}
20276 v8::Isolate* isolate = v8::Isolate::New();
20277 result_ = CalcFibonacci(isolate, fib_limit_);
20278 isolate->Dispose();
20281 int result() { return result_; }
20289 TEST(MultipleIsolatesOnIndividualThreads) {
20290 IsolateThread thread1(21);
20291 IsolateThread thread2(12);
20293 // Compute some fibonacci numbers on 3 threads in 3 isolates.
20297 int result1 = CalcFibonacci(CcTest::isolate(), 21);
20298 int result2 = CalcFibonacci(CcTest::isolate(), 12);
20303 // Compare results. The actual fibonacci numbers for 12 and 21 are taken
20304 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number
20305 CHECK_EQ(result1, 10946);
20306 CHECK_EQ(result2, 144);
20307 CHECK_EQ(result1, thread1.result());
20308 CHECK_EQ(result2, thread2.result());
20312 TEST(IsolateDifferentContexts) {
20313 v8::Isolate* isolate = v8::Isolate::New();
20314 Local<v8::Context> context;
20316 v8::Isolate::Scope isolate_scope(isolate);
20317 v8::HandleScope handle_scope(isolate);
20318 context = v8::Context::New(isolate);
20319 v8::Context::Scope context_scope(context);
20320 Local<Value> v = CompileRun("2");
20321 CHECK(v->IsNumber());
20322 CHECK_EQ(2, static_cast<int>(v->NumberValue()));
20325 v8::Isolate::Scope isolate_scope(isolate);
20326 v8::HandleScope handle_scope(isolate);
20327 context = v8::Context::New(isolate);
20328 v8::Context::Scope context_scope(context);
20329 Local<Value> v = CompileRun("22");
20330 CHECK(v->IsNumber());
20331 CHECK_EQ(22, static_cast<int>(v->NumberValue()));
20333 isolate->Dispose();
20336 class InitDefaultIsolateThread : public v8::base::Thread {
20339 SetResourceConstraints,
20341 SetCounterFunction,
20342 SetCreateHistogramFunction,
20343 SetAddHistogramSampleFunction
20346 explicit InitDefaultIsolateThread(TestCase testCase)
20347 : Thread(Options("InitDefaultIsolateThread")),
20348 testCase_(testCase),
20352 v8::Isolate::CreateParams create_params;
20353 switch (testCase_) {
20354 case SetResourceConstraints: {
20355 create_params.constraints.set_max_semi_space_size(1);
20356 create_params.constraints.set_max_old_space_size(4);
20362 v8::Isolate* isolate = v8::Isolate::New(create_params);
20364 switch (testCase_) {
20365 case SetResourceConstraints:
20366 // Already handled in pre-Isolate-creation block.
20369 case SetFatalHandler:
20370 v8::V8::SetFatalErrorHandler(NULL);
20373 case SetCounterFunction:
20374 CcTest::isolate()->SetCounterFunction(NULL);
20377 case SetCreateHistogramFunction:
20378 CcTest::isolate()->SetCreateHistogramFunction(NULL);
20381 case SetAddHistogramSampleFunction:
20382 CcTest::isolate()->SetAddHistogramSampleFunction(NULL);
20386 isolate->Dispose();
20390 bool result() { return result_; }
20393 TestCase testCase_;
20398 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) {
20399 InitDefaultIsolateThread thread(testCase);
20402 CHECK_EQ(thread.result(), true);
20406 TEST(InitializeDefaultIsolateOnSecondaryThread1) {
20407 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints);
20411 TEST(InitializeDefaultIsolateOnSecondaryThread2) {
20412 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler);
20416 TEST(InitializeDefaultIsolateOnSecondaryThread3) {
20417 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction);
20421 TEST(InitializeDefaultIsolateOnSecondaryThread4) {
20422 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction);
20426 TEST(InitializeDefaultIsolateOnSecondaryThread5) {
20427 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction);
20431 TEST(StringCheckMultipleContexts) {
20433 "(function() { return \"a\".charAt(0); })()";
20436 // Run the code twice in the first context to initialize the call IC.
20437 LocalContext context1;
20438 v8::HandleScope scope(context1->GetIsolate());
20439 ExpectString(code, "a");
20440 ExpectString(code, "a");
20444 // Change the String.prototype in the second context and check
20445 // that the right function gets called.
20446 LocalContext context2;
20447 v8::HandleScope scope(context2->GetIsolate());
20448 CompileRun("String.prototype.charAt = function() { return \"not a\"; }");
20449 ExpectString(code, "not a");
20454 TEST(NumberCheckMultipleContexts) {
20456 "(function() { return (42).toString(); })()";
20459 // Run the code twice in the first context to initialize the call IC.
20460 LocalContext context1;
20461 v8::HandleScope scope(context1->GetIsolate());
20462 ExpectString(code, "42");
20463 ExpectString(code, "42");
20467 // Change the Number.prototype in the second context and check
20468 // that the right function gets called.
20469 LocalContext context2;
20470 v8::HandleScope scope(context2->GetIsolate());
20471 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }");
20472 ExpectString(code, "not 42");
20477 TEST(BooleanCheckMultipleContexts) {
20479 "(function() { return true.toString(); })()";
20482 // Run the code twice in the first context to initialize the call IC.
20483 LocalContext context1;
20484 v8::HandleScope scope(context1->GetIsolate());
20485 ExpectString(code, "true");
20486 ExpectString(code, "true");
20490 // Change the Boolean.prototype in the second context and check
20491 // that the right function gets called.
20492 LocalContext context2;
20493 v8::HandleScope scope(context2->GetIsolate());
20494 CompileRun("Boolean.prototype.toString = function() { return \"\"; }");
20495 ExpectString(code, "");
20500 TEST(DontDeleteCellLoadIC) {
20501 const char* function_code =
20502 "function readCell() { while (true) { return cell; } }";
20505 // Run the code twice in the first context to initialize the load
20506 // IC for a don't delete cell.
20507 LocalContext context1;
20508 v8::HandleScope scope(context1->GetIsolate());
20509 CompileRun("var cell = \"first\";");
20510 ExpectBoolean("delete cell", false);
20511 CompileRun(function_code);
20512 ExpectString("readCell()", "first");
20513 ExpectString("readCell()", "first");
20517 // Use a deletable cell in the second context.
20518 LocalContext context2;
20519 v8::HandleScope scope(context2->GetIsolate());
20520 CompileRun("cell = \"second\";");
20521 CompileRun(function_code);
20522 ExpectString("readCell()", "second");
20523 ExpectBoolean("delete cell", true);
20524 ExpectString("(function() {"
20526 " return readCell();"
20528 " return e.toString();"
20531 "ReferenceError: cell is not defined");
20532 CompileRun("cell = \"new_second\";");
20533 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20534 ExpectString("readCell()", "new_second");
20535 ExpectString("readCell()", "new_second");
20540 TEST(DontDeleteCellLoadICForceDelete) {
20541 const char* function_code =
20542 "function readCell() { while (true) { return cell; } }";
20544 // Run the code twice to initialize the load IC for a don't delete
20546 LocalContext context;
20547 v8::HandleScope scope(context->GetIsolate());
20548 CompileRun("var cell = \"value\";");
20549 ExpectBoolean("delete cell", false);
20550 CompileRun(function_code);
20551 ExpectString("readCell()", "value");
20552 ExpectString("readCell()", "value");
20554 // Delete the cell using the API and check the inlined code works
20556 CHECK(context->Global()->ForceDelete(v8_str("cell")));
20557 ExpectString("(function() {"
20559 " return readCell();"
20561 " return e.toString();"
20564 "ReferenceError: cell is not defined");
20568 TEST(DontDeleteCellLoadICAPI) {
20569 const char* function_code =
20570 "function readCell() { while (true) { return cell; } }";
20572 // Run the code twice to initialize the load IC for a don't delete
20573 // cell created using the API.
20574 LocalContext context;
20575 v8::HandleScope scope(context->GetIsolate());
20576 context->Global()->ForceSet(v8_str("cell"), v8_str("value"), v8::DontDelete);
20577 ExpectBoolean("delete cell", false);
20578 CompileRun(function_code);
20579 ExpectString("readCell()", "value");
20580 ExpectString("readCell()", "value");
20582 // Delete the cell using the API and check the inlined code works
20584 CHECK(context->Global()->ForceDelete(v8_str("cell")));
20585 ExpectString("(function() {"
20587 " return readCell();"
20589 " return e.toString();"
20592 "ReferenceError: cell is not defined");
20596 class Visitor42 : public v8::PersistentHandleVisitor {
20598 explicit Visitor42(v8::Persistent<v8::Object>* object)
20599 : counter_(0), object_(object) { }
20601 virtual void VisitPersistentHandle(Persistent<Value>* value,
20602 uint16_t class_id) {
20603 if (class_id != 42) return;
20604 CHECK_EQ(42, value->WrapperClassId());
20605 v8::Isolate* isolate = CcTest::isolate();
20606 v8::HandleScope handle_scope(isolate);
20607 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value);
20608 v8::Handle<v8::Value> object =
20609 v8::Local<v8::Object>::New(isolate, *object_);
20610 CHECK(handle->IsObject());
20611 CHECK_EQ(Handle<Object>::Cast(handle), object);
20616 v8::Persistent<v8::Object>* object_;
20620 TEST(PersistentHandleVisitor) {
20621 LocalContext context;
20622 v8::Isolate* isolate = context->GetIsolate();
20623 v8::HandleScope scope(isolate);
20624 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20625 CHECK_EQ(0, object.WrapperClassId());
20626 object.SetWrapperClassId(42);
20627 CHECK_EQ(42, object.WrapperClassId());
20629 Visitor42 visitor(&object);
20630 v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
20631 CHECK_EQ(1, visitor.counter_);
20637 TEST(WrapperClassId) {
20638 LocalContext context;
20639 v8::Isolate* isolate = context->GetIsolate();
20640 v8::HandleScope scope(isolate);
20641 v8::Persistent<v8::Object> object(isolate, v8::Object::New(isolate));
20642 CHECK_EQ(0, object.WrapperClassId());
20643 object.SetWrapperClassId(65535);
20644 CHECK_EQ(65535, object.WrapperClassId());
20649 TEST(PersistentHandleInNewSpaceVisitor) {
20650 LocalContext context;
20651 v8::Isolate* isolate = context->GetIsolate();
20652 v8::HandleScope scope(isolate);
20653 v8::Persistent<v8::Object> object1(isolate, v8::Object::New(isolate));
20654 CHECK_EQ(0, object1.WrapperClassId());
20655 object1.SetWrapperClassId(42);
20656 CHECK_EQ(42, object1.WrapperClassId());
20658 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20659 CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
20661 v8::Persistent<v8::Object> object2(isolate, v8::Object::New(isolate));
20662 CHECK_EQ(0, object2.WrapperClassId());
20663 object2.SetWrapperClassId(42);
20664 CHECK_EQ(42, object2.WrapperClassId());
20666 Visitor42 visitor(&object2);
20667 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor);
20668 CHECK_EQ(1, visitor.counter_);
20676 LocalContext context;
20677 v8::HandleScope scope(context->GetIsolate());
20679 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone);
20680 CHECK(re->IsRegExp());
20681 CHECK(re->GetSource()->Equals(v8_str("foo")));
20682 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20684 re = v8::RegExp::New(v8_str("bar"),
20685 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20686 v8::RegExp::kGlobal));
20687 CHECK(re->IsRegExp());
20688 CHECK(re->GetSource()->Equals(v8_str("bar")));
20689 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal,
20690 static_cast<int>(re->GetFlags()));
20692 re = v8::RegExp::New(v8_str("baz"),
20693 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20694 v8::RegExp::kMultiline));
20695 CHECK(re->IsRegExp());
20696 CHECK(re->GetSource()->Equals(v8_str("baz")));
20697 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20698 static_cast<int>(re->GetFlags()));
20700 re = CompileRun("/quux/").As<v8::RegExp>();
20701 CHECK(re->IsRegExp());
20702 CHECK(re->GetSource()->Equals(v8_str("quux")));
20703 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20705 re = CompileRun("/quux/gm").As<v8::RegExp>();
20706 CHECK(re->IsRegExp());
20707 CHECK(re->GetSource()->Equals(v8_str("quux")));
20708 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline,
20709 static_cast<int>(re->GetFlags()));
20711 // Override the RegExp constructor and check the API constructor
20713 CompileRun("RegExp = function() {}");
20715 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone);
20716 CHECK(re->IsRegExp());
20717 CHECK(re->GetSource()->Equals(v8_str("foobar")));
20718 CHECK_EQ(v8::RegExp::kNone, re->GetFlags());
20720 re = v8::RegExp::New(v8_str("foobarbaz"),
20721 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase |
20722 v8::RegExp::kMultiline));
20723 CHECK(re->IsRegExp());
20724 CHECK(re->GetSource()->Equals(v8_str("foobarbaz")));
20725 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline,
20726 static_cast<int>(re->GetFlags()));
20728 context->Global()->Set(v8_str("re"), re);
20729 ExpectTrue("re.test('FoobarbaZ')");
20731 // RegExps are objects on which you can set properties.
20732 re->Set(v8_str("property"), v8::Integer::New(context->GetIsolate(), 32));
20733 v8::Handle<v8::Value> value(CompileRun("re.property"));
20734 CHECK_EQ(32, value->Int32Value());
20736 v8::TryCatch try_catch;
20737 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone);
20738 CHECK(re.IsEmpty());
20739 CHECK(try_catch.HasCaught());
20740 context->Global()->Set(v8_str("ex"), try_catch.Exception());
20741 ExpectTrue("ex instanceof SyntaxError");
20745 THREADED_TEST(Equals) {
20746 LocalContext localContext;
20747 v8::HandleScope handleScope(localContext->GetIsolate());
20749 v8::Handle<v8::Object> globalProxy = localContext->Global();
20750 v8::Handle<Value> global = globalProxy->GetPrototype();
20752 CHECK(global->StrictEquals(global));
20753 CHECK(!global->StrictEquals(globalProxy));
20754 CHECK(!globalProxy->StrictEquals(global));
20755 CHECK(globalProxy->StrictEquals(globalProxy));
20757 CHECK(global->Equals(global));
20758 CHECK(!global->Equals(globalProxy));
20759 CHECK(!globalProxy->Equals(global));
20760 CHECK(globalProxy->Equals(globalProxy));
20764 static void Getter(v8::Local<v8::String> property,
20765 const v8::PropertyCallbackInfo<v8::Value>& info ) {
20766 info.GetReturnValue().Set(v8_str("42!"));
20770 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) {
20771 v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate());
20772 result->Set(0, v8_str("universalAnswer"));
20773 info.GetReturnValue().Set(result);
20777 TEST(NamedEnumeratorAndForIn) {
20778 LocalContext context;
20779 v8::Isolate* isolate = context->GetIsolate();
20780 v8::HandleScope handle_scope(isolate);
20781 v8::Context::Scope context_scope(context.local());
20783 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
20784 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
20785 context->Global()->Set(v8_str("o"), tmpl->NewInstance());
20786 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
20787 "var result = []; for (var k in o) result.push(k); result"));
20788 CHECK_EQ(1, result->Length());
20789 CHECK_EQ(v8_str("universalAnswer"), result->Get(0));
20793 TEST(DefinePropertyPostDetach) {
20794 LocalContext context;
20795 v8::HandleScope scope(context->GetIsolate());
20796 v8::Handle<v8::Object> proxy = context->Global();
20797 v8::Handle<v8::Function> define_property =
20798 CompileRun("(function() {"
20799 " Object.defineProperty("
20802 " { configurable: true, enumerable: true, value: 3 });"
20803 "})").As<Function>();
20804 context->DetachGlobal();
20805 define_property->Call(proxy, 0, NULL);
20809 static void InstallContextId(v8::Handle<Context> context, int id) {
20810 Context::Scope scope(context);
20811 CompileRun("Object.prototype").As<Object>()->
20812 Set(v8_str("context_id"), v8::Integer::New(context->GetIsolate(), id));
20816 static void CheckContextId(v8::Handle<Object> object, int expected) {
20817 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value());
20821 THREADED_TEST(CreationContext) {
20822 v8::Isolate* isolate = CcTest::isolate();
20823 HandleScope handle_scope(isolate);
20824 Handle<Context> context1 = Context::New(isolate);
20825 InstallContextId(context1, 1);
20826 Handle<Context> context2 = Context::New(isolate);
20827 InstallContextId(context2, 2);
20828 Handle<Context> context3 = Context::New(isolate);
20829 InstallContextId(context3, 3);
20831 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(isolate);
20833 Local<Object> object1;
20834 Local<Function> func1;
20836 Context::Scope scope(context1);
20837 object1 = Object::New(isolate);
20838 func1 = tmpl->GetFunction();
20841 Local<Object> object2;
20842 Local<Function> func2;
20844 Context::Scope scope(context2);
20845 object2 = Object::New(isolate);
20846 func2 = tmpl->GetFunction();
20849 Local<Object> instance1;
20850 Local<Object> instance2;
20853 Context::Scope scope(context3);
20854 instance1 = func1->NewInstance();
20855 instance2 = func2->NewInstance();
20858 CHECK(object1->CreationContext() == context1);
20859 CheckContextId(object1, 1);
20860 CHECK(func1->CreationContext() == context1);
20861 CheckContextId(func1, 1);
20862 CHECK(instance1->CreationContext() == context1);
20863 CheckContextId(instance1, 1);
20864 CHECK(object2->CreationContext() == context2);
20865 CheckContextId(object2, 2);
20866 CHECK(func2->CreationContext() == context2);
20867 CheckContextId(func2, 2);
20868 CHECK(instance2->CreationContext() == context2);
20869 CheckContextId(instance2, 2);
20872 Context::Scope scope(context1);
20873 CHECK(object1->CreationContext() == context1);
20874 CheckContextId(object1, 1);
20875 CHECK(func1->CreationContext() == context1);
20876 CheckContextId(func1, 1);
20877 CHECK(instance1->CreationContext() == context1);
20878 CheckContextId(instance1, 1);
20879 CHECK(object2->CreationContext() == context2);
20880 CheckContextId(object2, 2);
20881 CHECK(func2->CreationContext() == context2);
20882 CheckContextId(func2, 2);
20883 CHECK(instance2->CreationContext() == context2);
20884 CheckContextId(instance2, 2);
20888 Context::Scope scope(context2);
20889 CHECK(object1->CreationContext() == context1);
20890 CheckContextId(object1, 1);
20891 CHECK(func1->CreationContext() == context1);
20892 CheckContextId(func1, 1);
20893 CHECK(instance1->CreationContext() == context1);
20894 CheckContextId(instance1, 1);
20895 CHECK(object2->CreationContext() == context2);
20896 CheckContextId(object2, 2);
20897 CHECK(func2->CreationContext() == context2);
20898 CheckContextId(func2, 2);
20899 CHECK(instance2->CreationContext() == context2);
20900 CheckContextId(instance2, 2);
20905 THREADED_TEST(CreationContextOfJsFunction) {
20906 HandleScope handle_scope(CcTest::isolate());
20907 Handle<Context> context = Context::New(CcTest::isolate());
20908 InstallContextId(context, 1);
20910 Local<Object> function;
20912 Context::Scope scope(context);
20913 function = CompileRun("function foo() {}; foo").As<Object>();
20916 CHECK(function->CreationContext() == context);
20917 CheckContextId(function, 1);
20921 void HasOwnPropertyIndexedPropertyGetter(
20923 const v8::PropertyCallbackInfo<v8::Value>& info) {
20924 if (index == 42) info.GetReturnValue().Set(v8_str("yes"));
20928 void HasOwnPropertyNamedPropertyGetter(
20929 Local<String> property,
20930 const v8::PropertyCallbackInfo<v8::Value>& info) {
20931 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
20935 void HasOwnPropertyIndexedPropertyQuery(
20936 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) {
20937 if (index == 42) info.GetReturnValue().Set(1);
20941 void HasOwnPropertyNamedPropertyQuery(
20942 Local<String> property,
20943 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20944 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
20948 void HasOwnPropertyNamedPropertyQuery2(
20949 Local<String> property,
20950 const v8::PropertyCallbackInfo<v8::Integer>& info) {
20951 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
20955 void HasOwnPropertyAccessorGetter(
20956 Local<String> property,
20957 const v8::PropertyCallbackInfo<v8::Value>& info) {
20958 info.GetReturnValue().Set(v8_str("yes"));
20962 TEST(HasOwnProperty) {
20964 v8::Isolate* isolate = env->GetIsolate();
20965 v8::HandleScope scope(isolate);
20966 { // Check normal properties and defined getters.
20967 Handle<Value> value = CompileRun(
20970 " this.__defineGetter__('baz', function() { return 1; });"
20972 "function Bar() { "
20974 " this.__defineGetter__('bla', function() { return 2; });"
20976 "Bar.prototype = new Foo();"
20978 CHECK(value->IsObject());
20979 Handle<Object> object = value->ToObject();
20980 CHECK(object->Has(v8_str("foo")));
20981 CHECK(!object->HasOwnProperty(v8_str("foo")));
20982 CHECK(object->HasOwnProperty(v8_str("bar")));
20983 CHECK(object->Has(v8_str("baz")));
20984 CHECK(!object->HasOwnProperty(v8_str("baz")));
20985 CHECK(object->HasOwnProperty(v8_str("bla")));
20987 { // Check named getter interceptors.
20988 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20989 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
20990 Handle<Object> instance = templ->NewInstance();
20991 CHECK(!instance->HasOwnProperty(v8_str("42")));
20992 CHECK(instance->HasOwnProperty(v8_str("foo")));
20993 CHECK(!instance->HasOwnProperty(v8_str("bar")));
20995 { // Check indexed getter interceptors.
20996 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
20997 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
20998 Handle<Object> instance = templ->NewInstance();
20999 CHECK(instance->HasOwnProperty(v8_str("42")));
21000 CHECK(!instance->HasOwnProperty(v8_str("43")));
21001 CHECK(!instance->HasOwnProperty(v8_str("foo")));
21003 { // Check named query interceptors.
21004 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21005 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
21006 Handle<Object> instance = templ->NewInstance();
21007 CHECK(instance->HasOwnProperty(v8_str("foo")));
21008 CHECK(!instance->HasOwnProperty(v8_str("bar")));
21010 { // Check indexed query interceptors.
21011 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21012 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
21013 Handle<Object> instance = templ->NewInstance();
21014 CHECK(instance->HasOwnProperty(v8_str("42")));
21015 CHECK(!instance->HasOwnProperty(v8_str("41")));
21017 { // Check callbacks.
21018 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21019 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter);
21020 Handle<Object> instance = templ->NewInstance();
21021 CHECK(instance->HasOwnProperty(v8_str("foo")));
21022 CHECK(!instance->HasOwnProperty(v8_str("bar")));
21024 { // Check that query wins on disagreement.
21025 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21026 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
21028 HasOwnPropertyNamedPropertyQuery2);
21029 Handle<Object> instance = templ->NewInstance();
21030 CHECK(!instance->HasOwnProperty(v8_str("foo")));
21031 CHECK(instance->HasOwnProperty(v8_str("bar")));
21036 TEST(IndexedInterceptorWithStringProto) {
21037 v8::Isolate* isolate = CcTest::isolate();
21038 v8::HandleScope scope(isolate);
21039 Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21040 templ->SetIndexedPropertyHandler(NULL,
21042 HasOwnPropertyIndexedPropertyQuery);
21043 LocalContext context;
21044 context->Global()->Set(v8_str("obj"), templ->NewInstance());
21045 CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
21046 // These should be intercepted.
21047 CHECK(CompileRun("42 in obj")->BooleanValue());
21048 CHECK(CompileRun("'42' in obj")->BooleanValue());
21049 // These should fall through to the String prototype.
21050 CHECK(CompileRun("0 in obj")->BooleanValue());
21051 CHECK(CompileRun("'0' in obj")->BooleanValue());
21052 // And these should both fail.
21053 CHECK(!CompileRun("32 in obj")->BooleanValue());
21054 CHECK(!CompileRun("'32' in obj")->BooleanValue());
21058 void CheckCodeGenerationAllowed() {
21059 Handle<Value> result = CompileRun("eval('42')");
21060 CHECK_EQ(42, result->Int32Value());
21061 result = CompileRun("(function(e) { return e('42'); })(eval)");
21062 CHECK_EQ(42, result->Int32Value());
21063 result = CompileRun("var f = new Function('return 42'); f()");
21064 CHECK_EQ(42, result->Int32Value());
21068 void CheckCodeGenerationDisallowed() {
21069 TryCatch try_catch;
21071 Handle<Value> result = CompileRun("eval('42')");
21072 CHECK(result.IsEmpty());
21073 CHECK(try_catch.HasCaught());
21076 result = CompileRun("(function(e) { return e('42'); })(eval)");
21077 CHECK(result.IsEmpty());
21078 CHECK(try_catch.HasCaught());
21081 result = CompileRun("var f = new Function('return 42'); f()");
21082 CHECK(result.IsEmpty());
21083 CHECK(try_catch.HasCaught());
21087 bool CodeGenerationAllowed(Local<Context> context) {
21088 ApiTestFuzzer::Fuzz();
21093 bool CodeGenerationDisallowed(Local<Context> context) {
21094 ApiTestFuzzer::Fuzz();
21099 THREADED_TEST(AllowCodeGenFromStrings) {
21100 LocalContext context;
21101 v8::HandleScope scope(context->GetIsolate());
21103 // eval and the Function constructor allowed by default.
21104 CHECK(context->IsCodeGenerationFromStringsAllowed());
21105 CheckCodeGenerationAllowed();
21107 // Disallow eval and the Function constructor.
21108 context->AllowCodeGenerationFromStrings(false);
21109 CHECK(!context->IsCodeGenerationFromStringsAllowed());
21110 CheckCodeGenerationDisallowed();
21113 context->AllowCodeGenerationFromStrings(true);
21114 CheckCodeGenerationAllowed();
21116 // Disallow but setting a global callback that will allow the calls.
21117 context->AllowCodeGenerationFromStrings(false);
21118 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed);
21119 CHECK(!context->IsCodeGenerationFromStringsAllowed());
21120 CheckCodeGenerationAllowed();
21122 // Set a callback that disallows the code generation.
21123 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
21124 CHECK(!context->IsCodeGenerationFromStringsAllowed());
21125 CheckCodeGenerationDisallowed();
21129 TEST(SetErrorMessageForCodeGenFromStrings) {
21130 LocalContext context;
21131 v8::HandleScope scope(context->GetIsolate());
21132 TryCatch try_catch;
21134 Handle<String> message = v8_str("Message") ;
21135 Handle<String> expected_message = v8_str("Uncaught EvalError: Message");
21136 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed);
21137 context->AllowCodeGenerationFromStrings(false);
21138 context->SetErrorMessageForCodeGenerationFromStrings(message);
21139 Handle<Value> result = CompileRun("eval('42')");
21140 CHECK(result.IsEmpty());
21141 CHECK(try_catch.HasCaught());
21142 Handle<String> actual_message = try_catch.Message()->Get();
21143 CHECK(expected_message->Equals(actual_message));
21147 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
21151 THREADED_TEST(CallAPIFunctionOnNonObject) {
21152 LocalContext context;
21153 v8::Isolate* isolate = context->GetIsolate();
21154 v8::HandleScope scope(isolate);
21155 Handle<FunctionTemplate> templ =
21156 v8::FunctionTemplate::New(isolate, NonObjectThis);
21157 Handle<Function> function = templ->GetFunction();
21158 context->Global()->Set(v8_str("f"), function);
21159 TryCatch try_catch;
21160 CompileRun("f.call(2)");
21164 // Regression test for issue 1470.
21165 THREADED_TEST(ReadOnlyIndexedProperties) {
21166 v8::Isolate* isolate = CcTest::isolate();
21167 v8::HandleScope scope(isolate);
21168 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
21170 LocalContext context;
21171 Local<v8::Object> obj = templ->NewInstance();
21172 context->Global()->Set(v8_str("obj"), obj);
21173 obj->ForceSet(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly);
21174 obj->Set(v8_str("1"), v8_str("foobar"));
21175 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1")));
21176 obj->ForceSet(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly);
21177 obj->Set(v8_num(2), v8_str("foobar"));
21178 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2)));
21180 // Test non-smi case.
21181 obj->ForceSet(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly);
21182 obj->Set(v8_str("2000000000"), v8_str("foobar"));
21183 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000")));
21187 THREADED_TEST(Regress1516) {
21188 LocalContext context;
21189 v8::HandleScope scope(context->GetIsolate());
21191 { v8::HandleScope temp_scope(context->GetIsolate());
21192 CompileRun("({'a': 0})");
21196 { i::MapCache* map_cache =
21197 i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
21198 elements = map_cache->NumberOfElements();
21199 CHECK_LE(1, elements);
21202 CcTest::heap()->CollectAllGarbage(
21203 i::Heap::kAbortIncrementalMarkingMask);
21204 { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
21205 if (raw_map_cache != CcTest::heap()->undefined_value()) {
21206 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
21207 CHECK_GT(elements, map_cache->NumberOfElements());
21213 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global,
21215 v8::AccessType type,
21216 Local<Value> data) {
21217 // Only block read access to __proto__.
21218 if (type == v8::ACCESS_GET &&
21219 name->IsString() &&
21220 name->ToString()->Length() == 9 &&
21221 name->ToString()->Utf8Length() == 9) {
21223 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
21224 return strncmp(buffer, "__proto__", 9) != 0;
21231 THREADED_TEST(Regress93759) {
21232 v8::Isolate* isolate = CcTest::isolate();
21233 HandleScope scope(isolate);
21235 // Template for object with security check.
21236 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(isolate);
21237 // We don't do indexing, so any callback can be used for that.
21238 no_proto_template->SetAccessCheckCallbacks(
21239 BlockProtoNamedSecurityTestCallback,
21240 IndexedSecurityTestCallback);
21242 // Templates for objects with hidden prototypes and possibly security check.
21243 Local<FunctionTemplate> hidden_proto_template =
21244 v8::FunctionTemplate::New(isolate);
21245 hidden_proto_template->SetHiddenPrototype(true);
21247 Local<FunctionTemplate> protected_hidden_proto_template =
21248 v8::FunctionTemplate::New(isolate);
21249 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks(
21250 BlockProtoNamedSecurityTestCallback,
21251 IndexedSecurityTestCallback);
21252 protected_hidden_proto_template->SetHiddenPrototype(true);
21254 // Context for "foreign" objects used in test.
21255 Local<Context> context = v8::Context::New(isolate);
21258 // Plain object, no security check.
21259 Local<Object> simple_object = Object::New(isolate);
21261 // Object with explicit security check.
21262 Local<Object> protected_object =
21263 no_proto_template->NewInstance();
21265 // JSGlobalProxy object, always have security check.
21266 Local<Object> proxy_object =
21269 // Global object, the prototype of proxy_object. No security checks.
21270 Local<Object> global_object =
21271 proxy_object->GetPrototype()->ToObject();
21273 // Hidden prototype without security check.
21274 Local<Object> hidden_prototype =
21275 hidden_proto_template->GetFunction()->NewInstance();
21276 Local<Object> object_with_hidden =
21277 Object::New(isolate);
21278 object_with_hidden->SetPrototype(hidden_prototype);
21280 // Hidden prototype with security check on the hidden prototype.
21281 Local<Object> protected_hidden_prototype =
21282 protected_hidden_proto_template->GetFunction()->NewInstance();
21283 Local<Object> object_with_protected_hidden =
21284 Object::New(isolate);
21285 object_with_protected_hidden->SetPrototype(protected_hidden_prototype);
21289 // Template for object for second context. Values to test are put on it as
21291 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
21292 global_template->Set(v8_str("simple"), simple_object);
21293 global_template->Set(v8_str("protected"), protected_object);
21294 global_template->Set(v8_str("global"), global_object);
21295 global_template->Set(v8_str("proxy"), proxy_object);
21296 global_template->Set(v8_str("hidden"), object_with_hidden);
21297 global_template->Set(v8_str("phidden"), object_with_protected_hidden);
21299 LocalContext context2(NULL, global_template);
21301 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)");
21302 CHECK(result1->Equals(simple_object->GetPrototype()));
21304 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)");
21305 CHECK(result2.IsEmpty());
21307 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)");
21308 CHECK(result3->Equals(global_object->GetPrototype()));
21310 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)");
21311 CHECK(result4.IsEmpty());
21313 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
21314 CHECK(result5->Equals(
21315 object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
21317 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
21318 CHECK(result6.IsEmpty());
21322 THREADED_TEST(Regress125988) {
21323 v8::HandleScope scope(CcTest::isolate());
21324 Handle<FunctionTemplate> intercept = FunctionTemplate::New(CcTest::isolate());
21325 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter);
21327 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction());
21328 CompileRun("var a = new Object();"
21329 "var b = new Intercept();"
21330 "var c = new Object();"
21334 "for (var i = 0; i < 3; i++) c.x;");
21335 ExpectBoolean("c.hasOwnProperty('x')", false);
21336 ExpectInt32("c.x", 23);
21337 CompileRun("a.y = 42;"
21338 "for (var i = 0; i < 3; i++) c.x;");
21339 ExpectBoolean("c.hasOwnProperty('x')", false);
21340 ExpectInt32("c.x", 23);
21341 ExpectBoolean("c.hasOwnProperty('y')", false);
21342 ExpectInt32("c.y", 42);
21346 static void TestReceiver(Local<Value> expected_result,
21347 Local<Value> expected_receiver,
21348 const char* code) {
21349 Local<Value> result = CompileRun(code);
21350 CHECK(result->IsObject());
21351 CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
21352 CHECK(expected_result->Equals(result->ToObject()->Get(0)));
21356 THREADED_TEST(ForeignFunctionReceiver) {
21357 v8::Isolate* isolate = CcTest::isolate();
21358 HandleScope scope(isolate);
21360 // Create two contexts with different "id" properties ('i' and 'o').
21361 // Call a function both from its own context and from a the foreign
21362 // context, and see what "this" is bound to (returning both "this"
21363 // and "this.id" for comparison).
21365 Local<Context> foreign_context = v8::Context::New(isolate);
21366 foreign_context->Enter();
21367 Local<Value> foreign_function =
21368 CompileRun("function func() { return { 0: this.id, "
21370 " toString: function() { "
21377 CHECK(foreign_function->IsFunction());
21378 foreign_context->Exit();
21380 LocalContext context;
21382 Local<String> password = v8_str("Password");
21383 // Don't get hit by security checks when accessing foreign_context's
21384 // global receiver (aka. global proxy).
21385 context->SetSecurityToken(password);
21386 foreign_context->SetSecurityToken(password);
21388 Local<String> i = v8_str("i");
21389 Local<String> o = v8_str("o");
21390 Local<String> id = v8_str("id");
21392 CompileRun("function ownfunc() { return { 0: this.id, "
21394 " toString: function() { "
21401 context->Global()->Set(v8_str("func"), foreign_function);
21403 // Sanity check the contexts.
21404 CHECK(i->Equals(foreign_context->Global()->Get(id)));
21405 CHECK(o->Equals(context->Global()->Get(id)));
21407 // Checking local function's receiver.
21408 // Calling function using its call/apply methods.
21409 TestReceiver(o, context->Global(), "ownfunc.call()");
21410 TestReceiver(o, context->Global(), "ownfunc.apply()");
21411 // Making calls through built-in functions.
21412 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]");
21413 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]")));
21414 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]")));
21415 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]")));
21416 // Calling with environment record as base.
21417 TestReceiver(o, context->Global(), "ownfunc()");
21418 // Calling with no base.
21419 TestReceiver(o, context->Global(), "(1,ownfunc)()");
21421 // Checking foreign function return value.
21422 // Calling function using its call/apply methods.
21423 TestReceiver(i, foreign_context->Global(), "func.call()");
21424 TestReceiver(i, foreign_context->Global(), "func.apply()");
21425 // Calling function using another context's call/apply methods.
21426 TestReceiver(i, foreign_context->Global(),
21427 "Function.prototype.call.call(func)");
21428 TestReceiver(i, foreign_context->Global(),
21429 "Function.prototype.call.apply(func)");
21430 TestReceiver(i, foreign_context->Global(),
21431 "Function.prototype.apply.call(func)");
21432 TestReceiver(i, foreign_context->Global(),
21433 "Function.prototype.apply.apply(func)");
21434 // Making calls through built-in functions.
21435 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]");
21436 // ToString(func()) is func()[0], i.e., the returned this.id.
21437 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]")));
21438 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]")));
21439 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]")));
21441 // Calling with environment record as base.
21442 TestReceiver(i, foreign_context->Global(), "func()");
21443 // Calling with no base.
21444 TestReceiver(i, foreign_context->Global(), "(1,func)()");
21448 uint8_t callback_fired = 0;
21451 void CallCompletedCallback1() {
21452 v8::base::OS::Print("Firing callback 1.\n");
21453 callback_fired ^= 1; // Toggle first bit.
21457 void CallCompletedCallback2() {
21458 v8::base::OS::Print("Firing callback 2.\n");
21459 callback_fired ^= 2; // Toggle second bit.
21463 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) {
21464 int32_t level = args[0]->Int32Value();
21467 v8::base::OS::Print("Entering recursion level %d.\n", level);
21469 i::Vector<char> script_vector(script, sizeof(script));
21470 i::SNPrintF(script_vector, "recursion(%d)", level);
21471 CompileRun(script_vector.start());
21472 v8::base::OS::Print("Leaving recursion level %d.\n", level);
21473 CHECK_EQ(0, callback_fired);
21475 v8::base::OS::Print("Recursion ends.\n");
21476 CHECK_EQ(0, callback_fired);
21481 TEST(CallCompletedCallback) {
21483 v8::HandleScope scope(env->GetIsolate());
21484 v8::Handle<v8::FunctionTemplate> recursive_runtime =
21485 v8::FunctionTemplate::New(env->GetIsolate(), RecursiveCall);
21486 env->Global()->Set(v8_str("recursion"),
21487 recursive_runtime->GetFunction());
21488 // Adding the same callback a second time has no effect.
21489 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21490 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback1);
21491 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallback2);
21492 v8::base::OS::Print("--- Script (1) ---\n");
21493 Local<Script> script = v8::Script::Compile(
21494 v8::String::NewFromUtf8(env->GetIsolate(), "recursion(0)"));
21496 CHECK_EQ(3, callback_fired);
21498 v8::base::OS::Print("\n--- Script (2) ---\n");
21499 callback_fired = 0;
21500 env->GetIsolate()->RemoveCallCompletedCallback(CallCompletedCallback1);
21502 CHECK_EQ(2, callback_fired);
21504 v8::base::OS::Print("\n--- Function ---\n");
21505 callback_fired = 0;
21506 Local<Function> recursive_function =
21507 Local<Function>::Cast(env->Global()->Get(v8_str("recursion")));
21508 v8::Handle<Value> args[] = { v8_num(0) };
21509 recursive_function->Call(env->Global(), 1, args);
21510 CHECK_EQ(2, callback_fired);
21514 void CallCompletedCallbackNoException() {
21515 v8::HandleScope scope(CcTest::isolate());
21516 CompileRun("1+1;");
21520 void CallCompletedCallbackException() {
21521 v8::HandleScope scope(CcTest::isolate());
21522 CompileRun("throw 'second exception';");
21526 TEST(CallCompletedCallbackOneException) {
21528 v8::HandleScope scope(env->GetIsolate());
21529 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackNoException);
21530 CompileRun("throw 'exception';");
21534 TEST(CallCompletedCallbackTwoExceptions) {
21536 v8::HandleScope scope(env->GetIsolate());
21537 env->GetIsolate()->AddCallCompletedCallback(CallCompletedCallbackException);
21538 CompileRun("throw 'first exception';");
21542 static void MicrotaskOne(const v8::FunctionCallbackInfo<Value>& info) {
21543 v8::HandleScope scope(info.GetIsolate());
21544 CompileRun("ext1Calls++;");
21548 static void MicrotaskTwo(const v8::FunctionCallbackInfo<Value>& info) {
21549 v8::HandleScope scope(info.GetIsolate());
21550 CompileRun("ext2Calls++;");
21554 void* g_passed_to_three = NULL;
21557 static void MicrotaskThree(void* data) {
21558 g_passed_to_three = data;
21562 TEST(EnqueueMicrotask) {
21564 v8::HandleScope scope(env->GetIsolate());
21566 "var ext1Calls = 0;"
21567 "var ext2Calls = 0;");
21568 CompileRun("1+1;");
21569 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
21570 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21572 env->GetIsolate()->EnqueueMicrotask(
21573 Function::New(env->GetIsolate(), MicrotaskOne));
21574 CompileRun("1+1;");
21575 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21576 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21578 env->GetIsolate()->EnqueueMicrotask(
21579 Function::New(env->GetIsolate(), MicrotaskOne));
21580 env->GetIsolate()->EnqueueMicrotask(
21581 Function::New(env->GetIsolate(), MicrotaskTwo));
21582 CompileRun("1+1;");
21583 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21584 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21586 env->GetIsolate()->EnqueueMicrotask(
21587 Function::New(env->GetIsolate(), MicrotaskTwo));
21588 CompileRun("1+1;");
21589 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21590 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21592 CompileRun("1+1;");
21593 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21594 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21596 g_passed_to_three = NULL;
21597 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree);
21598 CompileRun("1+1;");
21599 CHECK_EQ(NULL, g_passed_to_three);
21600 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21601 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21604 env->GetIsolate()->EnqueueMicrotask(
21605 Function::New(env->GetIsolate(), MicrotaskOne));
21606 env->GetIsolate()->EnqueueMicrotask(MicrotaskThree, &dummy);
21607 env->GetIsolate()->EnqueueMicrotask(
21608 Function::New(env->GetIsolate(), MicrotaskTwo));
21609 CompileRun("1+1;");
21610 CHECK_EQ(&dummy, g_passed_to_three);
21611 CHECK_EQ(3, CompileRun("ext1Calls")->Int32Value());
21612 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21613 g_passed_to_three = NULL;
21617 static void MicrotaskExceptionOne(
21618 const v8::FunctionCallbackInfo<Value>& info) {
21619 v8::HandleScope scope(info.GetIsolate());
21620 CompileRun("exception1Calls++;");
21621 info.GetIsolate()->ThrowException(
21622 v8::Exception::Error(v8_str("first")));
21626 static void MicrotaskExceptionTwo(
21627 const v8::FunctionCallbackInfo<Value>& info) {
21628 v8::HandleScope scope(info.GetIsolate());
21629 CompileRun("exception2Calls++;");
21630 info.GetIsolate()->ThrowException(
21631 v8::Exception::Error(v8_str("second")));
21635 TEST(RunMicrotasksIgnoresThrownExceptions) {
21637 v8::Isolate* isolate = env->GetIsolate();
21638 v8::HandleScope scope(isolate);
21640 "var exception1Calls = 0;"
21641 "var exception2Calls = 0;");
21642 isolate->EnqueueMicrotask(
21643 Function::New(isolate, MicrotaskExceptionOne));
21644 isolate->EnqueueMicrotask(
21645 Function::New(isolate, MicrotaskExceptionTwo));
21646 TryCatch try_catch;
21647 CompileRun("1+1;");
21648 CHECK(!try_catch.HasCaught());
21649 CHECK_EQ(1, CompileRun("exception1Calls")->Int32Value());
21650 CHECK_EQ(1, CompileRun("exception2Calls")->Int32Value());
21654 TEST(SetAutorunMicrotasks) {
21656 v8::HandleScope scope(env->GetIsolate());
21658 "var ext1Calls = 0;"
21659 "var ext2Calls = 0;");
21660 CompileRun("1+1;");
21661 CHECK_EQ(0, CompileRun("ext1Calls")->Int32Value());
21662 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21664 env->GetIsolate()->EnqueueMicrotask(
21665 Function::New(env->GetIsolate(), MicrotaskOne));
21666 CompileRun("1+1;");
21667 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21668 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21670 env->GetIsolate()->SetAutorunMicrotasks(false);
21671 env->GetIsolate()->EnqueueMicrotask(
21672 Function::New(env->GetIsolate(), MicrotaskOne));
21673 env->GetIsolate()->EnqueueMicrotask(
21674 Function::New(env->GetIsolate(), MicrotaskTwo));
21675 CompileRun("1+1;");
21676 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21677 CHECK_EQ(0, CompileRun("ext2Calls")->Int32Value());
21679 env->GetIsolate()->RunMicrotasks();
21680 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21681 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21683 env->GetIsolate()->EnqueueMicrotask(
21684 Function::New(env->GetIsolate(), MicrotaskTwo));
21685 CompileRun("1+1;");
21686 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21687 CHECK_EQ(1, CompileRun("ext2Calls")->Int32Value());
21689 env->GetIsolate()->RunMicrotasks();
21690 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21691 CHECK_EQ(2, CompileRun("ext2Calls")->Int32Value());
21693 env->GetIsolate()->SetAutorunMicrotasks(true);
21694 env->GetIsolate()->EnqueueMicrotask(
21695 Function::New(env->GetIsolate(), MicrotaskTwo));
21696 CompileRun("1+1;");
21697 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21698 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21700 env->GetIsolate()->EnqueueMicrotask(
21701 Function::New(env->GetIsolate(), MicrotaskTwo));
21703 v8::Isolate::SuppressMicrotaskExecutionScope scope(env->GetIsolate());
21704 CompileRun("1+1;");
21705 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21706 CHECK_EQ(3, CompileRun("ext2Calls")->Int32Value());
21709 CompileRun("1+1;");
21710 CHECK_EQ(2, CompileRun("ext1Calls")->Int32Value());
21711 CHECK_EQ(4, CompileRun("ext2Calls")->Int32Value());
21715 TEST(RunMicrotasksWithoutEnteringContext) {
21716 v8::Isolate* isolate = CcTest::isolate();
21717 HandleScope handle_scope(isolate);
21718 isolate->SetAutorunMicrotasks(false);
21719 Handle<Context> context = Context::New(isolate);
21721 Context::Scope context_scope(context);
21722 CompileRun("var ext1Calls = 0;");
21723 isolate->EnqueueMicrotask(Function::New(isolate, MicrotaskOne));
21725 isolate->RunMicrotasks();
21727 Context::Scope context_scope(context);
21728 CHECK_EQ(1, CompileRun("ext1Calls")->Int32Value());
21730 isolate->SetAutorunMicrotasks(true);
21734 static void DebugEventInObserver(const v8::Debug::EventDetails& event_details) {
21735 v8::DebugEvent event = event_details.GetEvent();
21736 if (event != v8::Break) return;
21737 Handle<Object> exec_state = event_details.GetExecutionState();
21738 Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
21739 CompileRun("function f(id) { new FrameDetails(id, 0); }");
21740 Handle<Function> fun = Handle<Function>::Cast(
21741 CcTest::global()->Get(v8_str("f"))->ToObject());
21742 fun->Call(CcTest::global(), 1, &break_id);
21746 TEST(Regress385349) {
21747 i::FLAG_allow_natives_syntax = true;
21748 v8::Isolate* isolate = CcTest::isolate();
21749 HandleScope handle_scope(isolate);
21750 isolate->SetAutorunMicrotasks(false);
21751 Handle<Context> context = Context::New(isolate);
21752 v8::Debug::SetDebugEventListener(DebugEventInObserver);
21754 Context::Scope context_scope(context);
21755 CompileRun("var obj = {};"
21756 "Object.observe(obj, function(changes) { debugger; });"
21759 isolate->RunMicrotasks();
21760 isolate->SetAutorunMicrotasks(true);
21761 v8::Debug::SetDebugEventListener(NULL);
21766 static int probes_counter = 0;
21767 static int misses_counter = 0;
21768 static int updates_counter = 0;
21771 static int* LookupCounter(const char* name) {
21772 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) {
21773 return &probes_counter;
21774 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) {
21775 return &misses_counter;
21776 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) {
21777 return &updates_counter;
21783 static const char* kMegamorphicTestProgram =
21784 "function ClassA() { };"
21785 "function ClassB() { };"
21786 "ClassA.prototype.foo = function() { };"
21787 "ClassB.prototype.foo = function() { };"
21788 "function fooify(obj) { obj.foo(); };"
21789 "var a = new ClassA();"
21790 "var b = new ClassB();"
21791 "for (var i = 0; i < 10000; i++) {"
21798 static void StubCacheHelper(bool primary) {
21800 i::FLAG_native_code_counters = true;
21802 i::FLAG_test_primary_stub_cache = true;
21804 i::FLAG_test_secondary_stub_cache = true;
21806 i::FLAG_crankshaft = false;
21808 env->GetIsolate()->SetCounterFunction(LookupCounter);
21809 v8::HandleScope scope(env->GetIsolate());
21810 int initial_probes = probes_counter;
21811 int initial_misses = misses_counter;
21812 int initial_updates = updates_counter;
21813 CompileRun(kMegamorphicTestProgram);
21814 int probes = probes_counter - initial_probes;
21815 int misses = misses_counter - initial_misses;
21816 int updates = updates_counter - initial_updates;
21817 CHECK_LT(updates, 10);
21818 CHECK_LT(misses, 10);
21819 // TODO(verwaest): Update this test to overflow the degree of polymorphism
21820 // before megamorphism. The number of probes will only work once we teach the
21821 // serializer to embed references to counters in the stubs, given that the
21822 // megamorphic_stub_cache_probes is updated in a snapshot-generated stub.
21823 CHECK_GE(probes, 0);
21828 TEST(SecondaryStubCache) {
21829 StubCacheHelper(true);
21833 TEST(PrimaryStubCache) {
21834 StubCacheHelper(false);
21839 static int cow_arrays_created_runtime = 0;
21842 static int* LookupCounterCOWArrays(const char* name) {
21843 if (strcmp(name, "c:V8.COWArraysCreatedRuntime") == 0) {
21844 return &cow_arrays_created_runtime;
21851 TEST(CheckCOWArraysCreatedRuntimeCounter) {
21853 i::FLAG_native_code_counters = true;
21855 env->GetIsolate()->SetCounterFunction(LookupCounterCOWArrays);
21856 v8::HandleScope scope(env->GetIsolate());
21857 int initial_cow_arrays = cow_arrays_created_runtime;
21858 CompileRun("var o = [1, 2, 3];");
21859 CHECK_EQ(1, cow_arrays_created_runtime - initial_cow_arrays);
21860 CompileRun("var o = {foo: [4, 5, 6], bar: [3, 0]};");
21861 CHECK_EQ(3, cow_arrays_created_runtime - initial_cow_arrays);
21862 CompileRun("var o = {foo: [1, 2, 3, [4, 5, 6]], bar: 'hi'};");
21863 CHECK_EQ(4, cow_arrays_created_runtime - initial_cow_arrays);
21868 TEST(StaticGetters) {
21869 LocalContext context;
21870 i::Factory* factory = CcTest::i_isolate()->factory();
21871 v8::Isolate* isolate = CcTest::isolate();
21872 v8::HandleScope scope(isolate);
21873 i::Handle<i::Object> undefined_value = factory->undefined_value();
21874 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value);
21875 i::Handle<i::Object> null_value = factory->null_value();
21876 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value);
21877 i::Handle<i::Object> true_value = factory->true_value();
21878 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value);
21879 i::Handle<i::Object> false_value = factory->false_value();
21880 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value);
21884 UNINITIALIZED_TEST(IsolateEmbedderData) {
21885 CcTest::DisableAutomaticDispose();
21886 v8::Isolate* isolate = v8::Isolate::New();
21888 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
21889 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21890 CHECK_EQ(NULL, isolate->GetData(slot));
21891 CHECK_EQ(NULL, i_isolate->GetData(slot));
21893 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21894 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21895 isolate->SetData(slot, data);
21897 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21898 void* data = reinterpret_cast<void*>(0xacce55ed + slot);
21899 CHECK_EQ(data, isolate->GetData(slot));
21900 CHECK_EQ(data, i_isolate->GetData(slot));
21902 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21903 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21904 isolate->SetData(slot, data);
21906 for (uint32_t slot = 0; slot < v8::Isolate::GetNumberOfDataSlots(); ++slot) {
21907 void* data = reinterpret_cast<void*>(0xdecea5ed + slot);
21908 CHECK_EQ(data, isolate->GetData(slot));
21909 CHECK_EQ(data, i_isolate->GetData(slot));
21912 isolate->Dispose();
21916 TEST(StringEmpty) {
21917 LocalContext context;
21918 i::Factory* factory = CcTest::i_isolate()->factory();
21919 v8::Isolate* isolate = CcTest::isolate();
21920 v8::HandleScope scope(isolate);
21921 i::Handle<i::Object> empty_string = factory->empty_string();
21922 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string);
21926 static int instance_checked_getter_count = 0;
21927 static void InstanceCheckedGetter(
21928 Local<String> name,
21929 const v8::PropertyCallbackInfo<v8::Value>& info) {
21930 CHECK_EQ(name, v8_str("foo"));
21931 instance_checked_getter_count++;
21932 info.GetReturnValue().Set(v8_num(11));
21936 static int instance_checked_setter_count = 0;
21937 static void InstanceCheckedSetter(Local<String> name,
21938 Local<Value> value,
21939 const v8::PropertyCallbackInfo<void>& info) {
21940 CHECK_EQ(name, v8_str("foo"));
21941 CHECK_EQ(value, v8_num(23));
21942 instance_checked_setter_count++;
21946 static void CheckInstanceCheckedResult(int getters, int setters,
21947 bool expects_callbacks,
21948 TryCatch* try_catch) {
21949 if (expects_callbacks) {
21950 CHECK(!try_catch->HasCaught());
21951 CHECK_EQ(getters, instance_checked_getter_count);
21952 CHECK_EQ(setters, instance_checked_setter_count);
21954 CHECK(try_catch->HasCaught());
21955 CHECK_EQ(0, instance_checked_getter_count);
21956 CHECK_EQ(0, instance_checked_setter_count);
21958 try_catch->Reset();
21962 static void CheckInstanceCheckedAccessors(bool expects_callbacks) {
21963 instance_checked_getter_count = 0;
21964 instance_checked_setter_count = 0;
21965 TryCatch try_catch;
21967 // Test path through generic runtime code.
21968 CompileRun("obj.foo");
21969 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch);
21970 CompileRun("obj.foo = 23");
21971 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch);
21973 // Test path through generated LoadIC and StoredIC.
21974 CompileRun("function test_get(o) { o.foo; }"
21976 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch);
21977 CompileRun("test_get(obj);");
21978 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch);
21979 CompileRun("test_get(obj);");
21980 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch);
21981 CompileRun("function test_set(o) { o.foo = 23; }"
21983 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch);
21984 CompileRun("test_set(obj);");
21985 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch);
21986 CompileRun("test_set(obj);");
21987 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch);
21989 // Test path through optimized code.
21990 CompileRun("%OptimizeFunctionOnNextCall(test_get);"
21992 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch);
21993 CompileRun("%OptimizeFunctionOnNextCall(test_set);"
21995 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch);
21997 // Cleanup so that closures start out fresh in next check.
21998 CompileRun("%DeoptimizeFunction(test_get);"
21999 "%ClearFunctionTypeFeedback(test_get);"
22000 "%DeoptimizeFunction(test_set);"
22001 "%ClearFunctionTypeFeedback(test_set);");
22005 THREADED_TEST(InstanceCheckOnInstanceAccessor) {
22006 v8::internal::FLAG_allow_natives_syntax = true;
22007 LocalContext context;
22008 v8::HandleScope scope(context->GetIsolate());
22010 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22011 Local<ObjectTemplate> inst = templ->InstanceTemplate();
22012 inst->SetAccessor(v8_str("foo"),
22013 InstanceCheckedGetter, InstanceCheckedSetter,
22017 v8::AccessorSignature::New(context->GetIsolate(), templ));
22018 context->Global()->Set(v8_str("f"), templ->GetFunction());
22020 printf("Testing positive ...\n");
22021 CompileRun("var obj = new f();");
22022 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22023 CheckInstanceCheckedAccessors(true);
22025 printf("Testing negative ...\n");
22026 CompileRun("var obj = {};"
22027 "obj.__proto__ = new f();");
22028 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22029 CheckInstanceCheckedAccessors(false);
22033 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) {
22034 v8::internal::FLAG_allow_natives_syntax = true;
22035 LocalContext context;
22036 v8::HandleScope scope(context->GetIsolate());
22038 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22039 Local<ObjectTemplate> inst = templ->InstanceTemplate();
22040 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22041 inst->SetAccessor(v8_str("foo"),
22042 InstanceCheckedGetter, InstanceCheckedSetter,
22046 v8::AccessorSignature::New(context->GetIsolate(), templ));
22047 context->Global()->Set(v8_str("f"), templ->GetFunction());
22049 printf("Testing positive ...\n");
22050 CompileRun("var obj = new f();");
22051 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22052 CheckInstanceCheckedAccessors(true);
22054 printf("Testing negative ...\n");
22055 CompileRun("var obj = {};"
22056 "obj.__proto__ = new f();");
22057 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22058 CheckInstanceCheckedAccessors(false);
22062 THREADED_TEST(InstanceCheckOnPrototypeAccessor) {
22063 v8::internal::FLAG_allow_natives_syntax = true;
22064 LocalContext context;
22065 v8::HandleScope scope(context->GetIsolate());
22067 Local<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22068 Local<ObjectTemplate> proto = templ->PrototypeTemplate();
22069 proto->SetAccessor(v8_str("foo"), InstanceCheckedGetter,
22070 InstanceCheckedSetter, Handle<Value>(), v8::DEFAULT,
22072 v8::AccessorSignature::New(context->GetIsolate(), templ));
22073 context->Global()->Set(v8_str("f"), templ->GetFunction());
22075 printf("Testing positive ...\n");
22076 CompileRun("var obj = new f();");
22077 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22078 CheckInstanceCheckedAccessors(true);
22080 printf("Testing negative ...\n");
22081 CompileRun("var obj = {};"
22082 "obj.__proto__ = new f();");
22083 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22084 CheckInstanceCheckedAccessors(false);
22086 printf("Testing positive with modified prototype chain ...\n");
22087 CompileRun("var obj = new f();"
22089 "pro.__proto__ = obj.__proto__;"
22090 "obj.__proto__ = pro;");
22091 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj"))));
22092 CheckInstanceCheckedAccessors(true);
22096 TEST(TryFinallyMessage) {
22097 LocalContext context;
22098 v8::HandleScope scope(context->GetIsolate());
22100 // Test that the original error message is not lost if there is a
22101 // recursive call into Javascript is done in the finally block, e.g. to
22102 // initialize an IC. (crbug.com/129171)
22103 TryCatch try_catch;
22104 const char* trigger_ic =
22106 " throw new Error('test'); \n"
22109 " x++; \n" // Trigger an IC initialization here.
22111 CompileRun(trigger_ic);
22112 CHECK(try_catch.HasCaught());
22113 Local<Message> message = try_catch.Message();
22114 CHECK(!message.IsEmpty());
22115 CHECK_EQ(2, message->GetLineNumber());
22119 // Test that the original exception message is indeed overwritten if
22120 // a new error is thrown in the finally block.
22121 TryCatch try_catch;
22122 const char* throw_again =
22124 " throw new Error('test'); \n"
22128 " throw new Error('again'); \n" // This is the new uncaught error.
22130 CompileRun(throw_again);
22131 CHECK(try_catch.HasCaught());
22132 Local<Message> message = try_catch.Message();
22133 CHECK(!message.IsEmpty());
22134 CHECK_EQ(6, message->GetLineNumber());
22139 static void Helper137002(bool do_store,
22141 bool remove_accessor,
22142 bool interceptor) {
22143 LocalContext context;
22144 Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
22146 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
22148 templ->SetAccessor(v8_str("foo"),
22149 GetterWhichReturns42,
22150 SetterWhichSetsYOnThisTo23);
22152 context->Global()->Set(v8_str("obj"), templ->NewInstance());
22154 // Turn monomorphic on slow object with native accessor, then turn
22155 // polymorphic, finally optimize to create negative lookup and fail.
22156 CompileRun(do_store ?
22157 "function f(x) { x.foo = void 0; }" :
22158 "function f(x) { return x.foo; }");
22159 CompileRun("obj.y = void 0;");
22160 if (!interceptor) {
22161 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);");
22163 CompileRun("obj.__proto__ = null;"
22164 "f(obj); f(obj); f(obj);");
22166 CompileRun("f({});");
22168 CompileRun("obj.y = void 0;"
22169 "%OptimizeFunctionOnNextCall(f);");
22170 if (remove_accessor) {
22171 CompileRun("delete obj.foo;");
22173 CompileRun("var result = f(obj);");
22175 CompileRun("result = obj.y;");
22177 if (remove_accessor && !interceptor) {
22178 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined());
22180 CHECK_EQ(do_store ? 23 : 42,
22181 context->Global()->Get(v8_str("result"))->Int32Value());
22186 THREADED_TEST(Regress137002a) {
22187 i::FLAG_allow_natives_syntax = true;
22188 i::FLAG_compilation_cache = false;
22189 v8::HandleScope scope(CcTest::isolate());
22190 for (int i = 0; i < 16; i++) {
22191 Helper137002(i & 8, i & 4, i & 2, i & 1);
22196 THREADED_TEST(Regress137002b) {
22197 i::FLAG_allow_natives_syntax = true;
22198 LocalContext context;
22199 v8::Isolate* isolate = context->GetIsolate();
22200 v8::HandleScope scope(isolate);
22201 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22202 templ->SetAccessor(v8_str("foo"),
22203 GetterWhichReturns42,
22204 SetterWhichSetsYOnThisTo23);
22205 context->Global()->Set(v8_str("obj"), templ->NewInstance());
22207 // Turn monomorphic on slow object with native accessor, then just
22208 // delete the property and fail.
22209 CompileRun("function load(x) { return x.foo; }"
22210 "function store(x) { x.foo = void 0; }"
22211 "function keyed_load(x, key) { return x[key]; }"
22212 // Second version of function has a different source (add void 0)
22213 // so that it does not share code with the first version. This
22214 // ensures that the ICs are monomorphic.
22215 "function load2(x) { void 0; return x.foo; }"
22216 "function store2(x) { void 0; x.foo = void 0; }"
22217 "function keyed_load2(x, key) { void 0; return x[key]; }"
22220 "obj.__proto__ = null;"
22222 "subobj.y = void 0;"
22223 "subobj.__proto__ = obj;"
22224 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22226 // Make the ICs monomorphic.
22227 "load(obj); load(obj);"
22228 "load2(subobj); load2(subobj);"
22229 "store(obj); store(obj);"
22230 "store2(subobj); store2(subobj);"
22231 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');"
22232 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');"
22234 // Actually test the shiny new ICs and better not crash. This
22235 // serves as a regression test for issue 142088 as well.
22240 "keyed_load(obj, 'foo');"
22241 "keyed_load2(subobj, 'foo');"
22243 // Delete the accessor. It better not be called any more now.
22246 "subobj.y = void 0;"
22248 "var load_result = load(obj);"
22249 "var load_result2 = load2(subobj);"
22250 "var keyed_load_result = keyed_load(obj, 'foo');"
22251 "var keyed_load_result2 = keyed_load2(subobj, 'foo');"
22254 "var y_from_obj = obj.y;"
22255 "var y_from_subobj = subobj.y;");
22256 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined());
22257 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined());
22258 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined());
22259 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined());
22260 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined());
22261 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined());
22265 THREADED_TEST(Regress142088) {
22266 i::FLAG_allow_natives_syntax = true;
22267 LocalContext context;
22268 v8::Isolate* isolate = context->GetIsolate();
22269 v8::HandleScope scope(isolate);
22270 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22271 templ->SetAccessor(v8_str("foo"),
22272 GetterWhichReturns42,
22273 SetterWhichSetsYOnThisTo23);
22274 context->Global()->Set(v8_str("obj"), templ->NewInstance());
22276 CompileRun("function load(x) { return x.foo; }"
22277 "var o = Object.create(obj);"
22278 "%OptimizeObjectForAddingMultipleProperties(obj, 1);"
22279 "load(o); load(o); load(o); load(o);");
22283 THREADED_TEST(Regress3337) {
22284 LocalContext context;
22285 v8::Isolate* isolate = context->GetIsolate();
22286 v8::HandleScope scope(isolate);
22287 Local<v8::Object> o1 = Object::New(isolate);
22288 Local<v8::Object> o2 = Object::New(isolate);
22289 i::Handle<i::JSObject> io1 = v8::Utils::OpenHandle(*o1);
22290 i::Handle<i::JSObject> io2 = v8::Utils::OpenHandle(*o2);
22291 CHECK(io1->map() == io2->map());
22292 o1->SetIndexedPropertiesToExternalArrayData(
22293 NULL, v8::kExternalUint32Array, 0);
22294 o2->SetIndexedPropertiesToExternalArrayData(
22295 NULL, v8::kExternalUint32Array, 0);
22296 CHECK(io1->map() == io2->map());
22300 THREADED_TEST(Regress137496) {
22301 i::FLAG_expose_gc = true;
22302 LocalContext context;
22303 v8::HandleScope scope(context->GetIsolate());
22305 // Compile a try-finally clause where the finally block causes a GC
22306 // while there still is a message pending for external reporting.
22307 TryCatch try_catch;
22308 try_catch.SetVerbose(true);
22309 CompileRun("try { throw new Error(); } finally { gc(); }");
22310 CHECK(try_catch.HasCaught());
22314 THREADED_TEST(Regress149912) {
22315 LocalContext context;
22316 v8::HandleScope scope(context->GetIsolate());
22317 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22318 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22319 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
22320 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();");
22324 THREADED_TEST(Regress157124) {
22325 LocalContext context;
22326 v8::Isolate* isolate = context->GetIsolate();
22327 v8::HandleScope scope(isolate);
22328 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
22329 Local<Object> obj = templ->NewInstance();
22330 obj->GetIdentityHash();
22331 obj->DeleteHiddenValue(v8_str("Bug"));
22335 THREADED_TEST(Regress2535) {
22336 LocalContext context;
22337 v8::HandleScope scope(context->GetIsolate());
22338 Local<Value> set_value = CompileRun("new Set();");
22339 Local<Object> set_object(Local<Object>::Cast(set_value));
22340 CHECK_EQ(0, set_object->InternalFieldCount());
22341 Local<Value> map_value = CompileRun("new Map();");
22342 Local<Object> map_object(Local<Object>::Cast(map_value));
22343 CHECK_EQ(0, map_object->InternalFieldCount());
22347 THREADED_TEST(Regress2746) {
22348 LocalContext context;
22349 v8::Isolate* isolate = context->GetIsolate();
22350 v8::HandleScope scope(isolate);
22351 Local<Object> obj = Object::New(isolate);
22352 Local<String> key = String::NewFromUtf8(context->GetIsolate(), "key");
22353 obj->SetHiddenValue(key, v8::Undefined(isolate));
22354 Local<Value> value = obj->GetHiddenValue(key);
22355 CHECK(!value.IsEmpty());
22356 CHECK(value->IsUndefined());
22360 THREADED_TEST(Regress260106) {
22361 LocalContext context;
22362 v8::Isolate* isolate = context->GetIsolate();
22363 v8::HandleScope scope(isolate);
22364 Local<FunctionTemplate> templ = FunctionTemplate::New(isolate,
22366 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;");
22367 Local<Function> function = templ->GetFunction();
22368 CHECK(!function.IsEmpty());
22369 CHECK(function->IsFunction());
22373 THREADED_TEST(JSONParseObject) {
22374 LocalContext context;
22375 HandleScope scope(context->GetIsolate());
22376 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}"));
22377 Handle<Object> global = context->Global();
22378 global->Set(v8_str("obj"), obj);
22379 ExpectString("JSON.stringify(obj)", "{\"x\":42}");
22383 THREADED_TEST(JSONParseNumber) {
22384 LocalContext context;
22385 HandleScope scope(context->GetIsolate());
22386 Local<Value> obj = v8::JSON::Parse(v8_str("42"));
22387 Handle<Object> global = context->Global();
22388 global->Set(v8_str("obj"), obj);
22389 ExpectString("JSON.stringify(obj)", "42");
22393 #if V8_OS_POSIX && !V8_OS_NACL
22394 class ThreadInterruptTest {
22396 ThreadInterruptTest() : sem_(0), sem_value_(0) { }
22397 ~ThreadInterruptTest() {}
22400 InterruptThread i_thread(this);
22404 CHECK_EQ(kExpectedValue, sem_value_);
22408 static const int kExpectedValue = 1;
22410 class InterruptThread : public v8::base::Thread {
22412 explicit InterruptThread(ThreadInterruptTest* test)
22413 : Thread(Options("InterruptThread")), test_(test) {}
22415 virtual void Run() {
22416 struct sigaction action;
22418 // Ensure that we'll enter waiting condition
22419 v8::base::OS::Sleep(100);
22421 // Setup signal handler
22422 memset(&action, 0, sizeof(action));
22423 action.sa_handler = SignalHandler;
22424 sigaction(SIGCHLD, &action, NULL);
22427 kill(getpid(), SIGCHLD);
22429 // Ensure that if wait has returned because of error
22430 v8::base::OS::Sleep(100);
22432 // Set value and signal semaphore
22433 test_->sem_value_ = 1;
22434 test_->sem_.Signal();
22437 static void SignalHandler(int signal) {
22441 ThreadInterruptTest* test_;
22444 v8::base::Semaphore sem_;
22445 volatile int sem_value_;
22449 THREADED_TEST(SemaphoreInterruption) {
22450 ThreadInterruptTest().RunTest();
22454 #endif // V8_OS_POSIX
22457 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global,
22459 v8::AccessType type,
22460 Local<Value> data) {
22461 i::PrintF("Named access blocked.\n");
22466 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global,
22468 v8::AccessType type,
22469 Local<Value> data) {
22470 i::PrintF("Indexed access blocked.\n");
22475 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22480 TEST(JSONStringifyAccessCheck) {
22481 v8::V8::Initialize();
22482 v8::Isolate* isolate = CcTest::isolate();
22483 v8::HandleScope scope(isolate);
22485 // Create an ObjectTemplate for global objects and install access
22486 // check callbacks that will block access.
22487 v8::Handle<v8::ObjectTemplate> global_template =
22488 v8::ObjectTemplate::New(isolate);
22489 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
22490 IndexAccessAlwaysBlocked);
22492 // Create a context and set an x property on it's global object.
22493 LocalContext context0(NULL, global_template);
22494 v8::Handle<v8::Object> global0 = context0->Global();
22495 global0->Set(v8_str("x"), v8_num(42));
22496 ExpectString("JSON.stringify(this)", "{\"x\":42}");
22498 for (int i = 0; i < 2; i++) {
22500 // Install a toJSON function on the second run.
22501 v8::Handle<v8::FunctionTemplate> toJSON =
22502 v8::FunctionTemplate::New(isolate, UnreachableCallback);
22504 global0->Set(v8_str("toJSON"), toJSON->GetFunction());
22506 // Create a context with a different security token so that the
22507 // failed access check callback will be called on each access.
22508 LocalContext context1(NULL, global_template);
22509 context1->Global()->Set(v8_str("other"), global0);
22511 CHECK(CompileRun("JSON.stringify(other)").IsEmpty());
22512 CHECK(CompileRun("JSON.stringify({ 'a' : other, 'b' : ['c'] })").IsEmpty());
22513 CHECK(CompileRun("JSON.stringify([other, 'b', 'c'])").IsEmpty());
22515 v8::Handle<v8::Array> array = v8::Array::New(isolate, 2);
22516 array->Set(0, v8_str("a"));
22517 array->Set(1, v8_str("b"));
22518 context1->Global()->Set(v8_str("array"), array);
22519 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]");
22520 array->TurnOnAccessCheck();
22521 CHECK(CompileRun("JSON.stringify(array)").IsEmpty());
22522 CHECK(CompileRun("JSON.stringify([array])").IsEmpty());
22523 CHECK(CompileRun("JSON.stringify({'a' : array})").IsEmpty());
22528 bool access_check_fail_thrown = false;
22529 bool catch_callback_called = false;
22532 // Failed access check callback that performs a GC on each invocation.
22533 void FailedAccessCheckThrows(Local<v8::Object> target,
22534 v8::AccessType type,
22535 Local<v8::Value> data) {
22536 access_check_fail_thrown = true;
22537 i::PrintF("Access check failed. Error thrown.\n");
22538 CcTest::isolate()->ThrowException(
22539 v8::Exception::Error(v8_str("cross context")));
22543 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22544 for (int i = 0; i < args.Length(); i++) {
22545 i::PrintF("%s\n", *String::Utf8Value(args[i]));
22547 catch_callback_called = true;
22551 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
22552 args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
22556 void CheckCorrectThrow(const char* script) {
22557 // Test that the script, when wrapped into a try-catch, triggers the catch
22558 // clause due to failed access check throwing an exception.
22559 // The subsequent try-catch should run without any exception.
22560 access_check_fail_thrown = false;
22561 catch_callback_called = false;
22562 i::ScopedVector<char> source(1024);
22563 i::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script);
22564 CompileRun(source.start());
22565 CHECK(access_check_fail_thrown);
22566 CHECK(catch_callback_called);
22568 access_check_fail_thrown = false;
22569 catch_callback_called = false;
22570 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };");
22571 CHECK(!access_check_fail_thrown);
22572 CHECK(!catch_callback_called);
22576 TEST(AccessCheckThrows) {
22577 i::FLAG_allow_natives_syntax = true;
22578 v8::V8::Initialize();
22579 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows);
22580 v8::Isolate* isolate = CcTest::isolate();
22581 v8::HandleScope scope(isolate);
22583 // Create an ObjectTemplate for global objects and install access
22584 // check callbacks that will block access.
22585 v8::Handle<v8::ObjectTemplate> global_template =
22586 v8::ObjectTemplate::New(isolate);
22587 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked,
22588 IndexAccessAlwaysBlocked);
22590 // Create a context and set an x property on it's global object.
22591 LocalContext context0(NULL, global_template);
22592 v8::Handle<v8::Object> global0 = context0->Global();
22594 // Create a context with a different security token so that the
22595 // failed access check callback will be called on each access.
22596 LocalContext context1(NULL, global_template);
22597 context1->Global()->Set(v8_str("other"), global0);
22599 v8::Handle<v8::FunctionTemplate> catcher_fun =
22600 v8::FunctionTemplate::New(isolate, CatcherCallback);
22601 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction());
22603 v8::Handle<v8::FunctionTemplate> has_own_property_fun =
22604 v8::FunctionTemplate::New(isolate, HasOwnPropertyCallback);
22605 context1->Global()->Set(v8_str("has_own_property"),
22606 has_own_property_fun->GetFunction());
22608 { v8::TryCatch try_catch;
22609 access_check_fail_thrown = false;
22610 CompileRun("other.x;");
22611 CHECK(access_check_fail_thrown);
22612 CHECK(try_catch.HasCaught());
22615 CheckCorrectThrow("other.x");
22616 CheckCorrectThrow("other[1]");
22617 CheckCorrectThrow("JSON.stringify(other)");
22618 CheckCorrectThrow("has_own_property(other, 'x')");
22619 CheckCorrectThrow("%GetProperty(other, 'x')");
22620 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 0)");
22621 CheckCorrectThrow("%AddNamedProperty(other, 'x', 'foo', 1)");
22622 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)");
22623 CheckCorrectThrow("%DeleteProperty(other, '1', 0)");
22624 CheckCorrectThrow("%HasOwnProperty(other, 'x')");
22625 CheckCorrectThrow("%HasProperty(other, 'x')");
22626 CheckCorrectThrow("%HasElement(other, 1)");
22627 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')");
22628 CheckCorrectThrow("%GetPropertyNames(other)");
22629 // PROPERTY_ATTRIBUTES_NONE = 0
22630 CheckCorrectThrow("%GetOwnPropertyNames(other, 0)");
22631 CheckCorrectThrow("%DefineAccessorPropertyUnchecked("
22632 "other, 'x', null, null, 1)");
22634 // Reset the failed access check callback so it does not influence
22635 // the other tests.
22636 v8::V8::SetFailedAccessCheckCallbackFunction(NULL);
22640 THREADED_TEST(Regress256330) {
22641 i::FLAG_allow_natives_syntax = true;
22642 LocalContext context;
22643 v8::HandleScope scope(context->GetIsolate());
22644 Handle<FunctionTemplate> templ = FunctionTemplate::New(context->GetIsolate());
22645 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter);
22646 context->Global()->Set(v8_str("Bug"), templ->GetFunction());
22647 CompileRun("\"use strict\"; var o = new Bug;"
22648 "function f(o) { o.x = 10; };"
22649 "f(o); f(o); f(o);"
22650 "%OptimizeFunctionOnNextCall(f);"
22652 ExpectBoolean("%GetOptimizationStatus(f) != 2", true);
22656 THREADED_TEST(CrankshaftInterceptorSetter) {
22657 i::FLAG_allow_natives_syntax = true;
22658 v8::HandleScope scope(CcTest::isolate());
22659 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22660 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22662 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22663 CompileRun("var obj = new Obj;"
22664 // Initialize fields to avoid transitions later.
22666 "obj.accessor_age = 42;"
22667 "function setter(i) { this.accessor_age = i; };"
22668 "function getter() { return this.accessor_age; };"
22669 "function setAge(i) { obj.age = i; };"
22670 "Object.defineProperty(obj, 'age', { get:getter, set:setter });"
22674 "%OptimizeFunctionOnNextCall(setAge);"
22676 // All stores went through the interceptor.
22677 ExpectInt32("obj.interceptor_age", 4);
22678 ExpectInt32("obj.accessor_age", 42);
22682 THREADED_TEST(CrankshaftInterceptorGetter) {
22683 i::FLAG_allow_natives_syntax = true;
22684 v8::HandleScope scope(CcTest::isolate());
22685 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22686 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22688 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22689 CompileRun("var obj = new Obj;"
22690 // Initialize fields to avoid transitions later.
22692 "obj.accessor_age = 42;"
22693 "function getter() { return this.accessor_age; };"
22694 "function getAge() { return obj.interceptor_age; };"
22695 "Object.defineProperty(obj, 'interceptor_age', { get:getter });"
22699 "%OptimizeFunctionOnNextCall(getAge);");
22700 // Access through interceptor.
22701 ExpectInt32("getAge()", 1);
22705 THREADED_TEST(CrankshaftInterceptorFieldRead) {
22706 i::FLAG_allow_natives_syntax = true;
22707 v8::HandleScope scope(CcTest::isolate());
22708 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22709 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22711 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22712 CompileRun("var obj = new Obj;"
22713 "obj.__proto__.interceptor_age = 42;"
22715 "function getAge() { return obj.interceptor_age; };");
22716 ExpectInt32("getAge();", 100);
22717 ExpectInt32("getAge();", 100);
22718 ExpectInt32("getAge();", 100);
22719 CompileRun("%OptimizeFunctionOnNextCall(getAge);");
22720 // Access through interceptor.
22721 ExpectInt32("getAge();", 100);
22725 THREADED_TEST(CrankshaftInterceptorFieldWrite) {
22726 i::FLAG_allow_natives_syntax = true;
22727 v8::HandleScope scope(CcTest::isolate());
22728 Handle<FunctionTemplate> templ = FunctionTemplate::New(CcTest::isolate());
22729 AddInterceptor(templ, InterceptorGetter, InterceptorSetter);
22731 env->Global()->Set(v8_str("Obj"), templ->GetFunction());
22732 CompileRun("var obj = new Obj;"
22733 "obj.age = 100000;"
22734 "function setAge(i) { obj.age = i };"
22738 "%OptimizeFunctionOnNextCall(setAge);"
22740 ExpectInt32("obj.age", 100000);
22741 ExpectInt32("obj.interceptor_age", 103);
22745 class RequestInterruptTestBase {
22747 RequestInterruptTestBase()
22749 isolate_(env_->GetIsolate()),
22752 should_continue_(true) {
22755 virtual ~RequestInterruptTestBase() { }
22757 virtual void StartInterruptThread() = 0;
22759 virtual void TestBody() = 0;
22762 StartInterruptThread();
22764 v8::HandleScope handle_scope(isolate_);
22768 isolate_->ClearInterrupt();
22770 // Verify we arrived here because interruptor was called
22771 // not due to a bug causing us to exit the loop too early.
22772 CHECK(!should_continue());
22775 void WakeUpInterruptor() {
22779 bool should_continue() const { return should_continue_; }
22781 bool ShouldContinue() {
22783 if (--warmup_ == 0) {
22784 WakeUpInterruptor();
22788 return should_continue_;
22791 static void ShouldContinueCallback(
22792 const v8::FunctionCallbackInfo<Value>& info) {
22793 RequestInterruptTestBase* test =
22794 reinterpret_cast<RequestInterruptTestBase*>(
22795 info.Data().As<v8::External>()->Value());
22796 info.GetReturnValue().Set(test->ShouldContinue());
22800 v8::Isolate* isolate_;
22801 v8::base::Semaphore sem_;
22803 bool should_continue_;
22807 class RequestInterruptTestBaseWithSimpleInterrupt
22808 : public RequestInterruptTestBase {
22810 RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
22812 virtual void StartInterruptThread() {
22817 class InterruptThread : public v8::base::Thread {
22819 explicit InterruptThread(RequestInterruptTestBase* test)
22820 : Thread(Options("RequestInterruptTest")), test_(test) {}
22822 virtual void Run() {
22823 test_->sem_.Wait();
22824 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
22827 static void OnInterrupt(v8::Isolate* isolate, void* data) {
22828 reinterpret_cast<RequestInterruptTestBase*>(data)->
22829 should_continue_ = false;
22833 RequestInterruptTestBase* test_;
22836 InterruptThread i_thread;
22840 class RequestInterruptTestWithFunctionCall
22841 : public RequestInterruptTestBaseWithSimpleInterrupt {
22843 virtual void TestBody() {
22844 Local<Function> func = Function::New(
22845 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
22846 env_->Global()->Set(v8_str("ShouldContinue"), func);
22848 CompileRun("while (ShouldContinue()) { }");
22853 class RequestInterruptTestWithMethodCall
22854 : public RequestInterruptTestBaseWithSimpleInterrupt {
22856 virtual void TestBody() {
22857 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22858 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22859 proto->Set(v8_str("shouldContinue"), Function::New(
22860 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22861 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22863 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22868 class RequestInterruptTestWithAccessor
22869 : public RequestInterruptTestBaseWithSimpleInterrupt {
22871 virtual void TestBody() {
22872 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22873 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22874 proto->SetAccessorProperty(v8_str("shouldContinue"), FunctionTemplate::New(
22875 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22876 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22878 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22883 class RequestInterruptTestWithNativeAccessor
22884 : public RequestInterruptTestBaseWithSimpleInterrupt {
22886 virtual void TestBody() {
22887 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22888 t->InstanceTemplate()->SetNativeDataProperty(
22889 v8_str("shouldContinue"),
22890 &ShouldContinueNativeGetter,
22892 v8::External::New(isolate_, this));
22893 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22895 CompileRun("var obj = new Klass; while (obj.shouldContinue) { }");
22899 static void ShouldContinueNativeGetter(
22900 Local<String> property,
22901 const v8::PropertyCallbackInfo<v8::Value>& info) {
22902 RequestInterruptTestBase* test =
22903 reinterpret_cast<RequestInterruptTestBase*>(
22904 info.Data().As<v8::External>()->Value());
22905 info.GetReturnValue().Set(test->ShouldContinue());
22910 class RequestInterruptTestWithMethodCallAndInterceptor
22911 : public RequestInterruptTestBaseWithSimpleInterrupt {
22913 virtual void TestBody() {
22914 v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
22915 v8::Local<v8::Template> proto = t->PrototypeTemplate();
22916 proto->Set(v8_str("shouldContinue"), Function::New(
22917 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
22918 v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
22919 instance_template->SetNamedPropertyHandler(EmptyInterceptor);
22921 env_->Global()->Set(v8_str("Klass"), t->GetFunction());
22923 CompileRun("var obj = new Klass; while (obj.shouldContinue()) { }");
22927 static void EmptyInterceptor(
22928 Local<String> property,
22929 const v8::PropertyCallbackInfo<v8::Value>& info) {
22934 class RequestInterruptTestWithMathAbs
22935 : public RequestInterruptTestBaseWithSimpleInterrupt {
22937 virtual void TestBody() {
22938 env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
22940 WakeUpInterruptorCallback,
22941 v8::External::New(isolate_, this)));
22943 env_->Global()->Set(v8_str("ShouldContinue"), Function::New(
22945 ShouldContinueCallback,
22946 v8::External::New(isolate_, this)));
22948 i::FLAG_allow_natives_syntax = true;
22949 CompileRun("function loopish(o) {"
22951 " while (o.abs(1) > 0) {"
22952 " if (o.abs(1) >= 0 && !ShouldContinue()) break;"
22954 " if (--pre === 0) WakeUpInterruptor(o === Math);"
22959 "var obj = {abs: function () { return i-- }, x: null};"
22962 "%OptimizeFunctionOnNextCall(loopish);"
22965 i::FLAG_allow_natives_syntax = false;
22969 static void WakeUpInterruptorCallback(
22970 const v8::FunctionCallbackInfo<Value>& info) {
22971 if (!info[0]->BooleanValue()) return;
22973 RequestInterruptTestBase* test =
22974 reinterpret_cast<RequestInterruptTestBase*>(
22975 info.Data().As<v8::External>()->Value());
22976 test->WakeUpInterruptor();
22979 static void ShouldContinueCallback(
22980 const v8::FunctionCallbackInfo<Value>& info) {
22981 RequestInterruptTestBase* test =
22982 reinterpret_cast<RequestInterruptTestBase*>(
22983 info.Data().As<v8::External>()->Value());
22984 info.GetReturnValue().Set(test->should_continue());
22989 TEST(RequestInterruptTestWithFunctionCall) {
22990 RequestInterruptTestWithFunctionCall().RunTest();
22994 TEST(RequestInterruptTestWithMethodCall) {
22995 RequestInterruptTestWithMethodCall().RunTest();
22999 TEST(RequestInterruptTestWithAccessor) {
23000 RequestInterruptTestWithAccessor().RunTest();
23004 TEST(RequestInterruptTestWithNativeAccessor) {
23005 RequestInterruptTestWithNativeAccessor().RunTest();
23009 TEST(RequestInterruptTestWithMethodCallAndInterceptor) {
23010 RequestInterruptTestWithMethodCallAndInterceptor().RunTest();
23014 TEST(RequestInterruptTestWithMathAbs) {
23015 RequestInterruptTestWithMathAbs().RunTest();
23019 class ClearInterruptFromAnotherThread
23020 : public RequestInterruptTestBase {
23022 ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
23024 virtual void StartInterruptThread() {
23028 virtual void TestBody() {
23029 Local<Function> func = Function::New(
23030 isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
23031 env_->Global()->Set(v8_str("ShouldContinue"), func);
23033 CompileRun("while (ShouldContinue()) { }");
23037 class InterruptThread : public v8::base::Thread {
23039 explicit InterruptThread(ClearInterruptFromAnotherThread* test)
23040 : Thread(Options("RequestInterruptTest")), test_(test) {}
23042 virtual void Run() {
23043 test_->sem_.Wait();
23044 test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
23045 test_->sem_.Wait();
23046 test_->isolate_->ClearInterrupt();
23047 test_->sem2_.Signal();
23050 static void OnInterrupt(v8::Isolate* isolate, void* data) {
23051 ClearInterruptFromAnotherThread* test =
23052 reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
23053 test->sem_.Signal();
23054 bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
23055 // Crash instead of timeout to make this failure more prominent.
23057 test->should_continue_ = false;
23061 ClearInterruptFromAnotherThread* test_;
23064 InterruptThread i_thread;
23065 v8::base::Semaphore sem2_;
23069 TEST(ClearInterruptFromAnotherThread) {
23070 ClearInterruptFromAnotherThread().RunTest();
23074 static Local<Value> function_new_expected_env;
23075 static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
23076 CHECK_EQ(function_new_expected_env, info.Data());
23077 info.GetReturnValue().Set(17);
23081 THREADED_TEST(FunctionNew) {
23083 v8::Isolate* isolate = env->GetIsolate();
23084 v8::HandleScope scope(isolate);
23085 Local<Object> data = v8::Object::New(isolate);
23086 function_new_expected_env = data;
23087 Local<Function> func = Function::New(isolate, FunctionNewCallback, data);
23088 env->Global()->Set(v8_str("func"), func);
23089 Local<Value> result = CompileRun("func();");
23090 CHECK_EQ(v8::Integer::New(isolate, 17), result);
23091 // Verify function not cached
23092 int serial_number =
23093 i::Smi::cast(v8::Utils::OpenHandle(*func)
23094 ->shared()->get_api_func_data()->serial_number())->value();
23095 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
23096 i::Handle<i::JSObject> cache(i_isolate->native_context()->function_cache());
23097 i::Handle<i::Object> elm =
23098 i::Object::GetElement(i_isolate, cache, serial_number).ToHandleChecked();
23099 CHECK(elm->IsUndefined());
23100 // Verify that each Function::New creates a new function instance
23101 Local<Object> data2 = v8::Object::New(isolate);
23102 function_new_expected_env = data2;
23103 Local<Function> func2 = Function::New(isolate, FunctionNewCallback, data2);
23104 CHECK(!func2->IsNull());
23105 CHECK_NE(func, func2);
23106 env->Global()->Set(v8_str("func2"), func2);
23107 Local<Value> result2 = CompileRun("func2();");
23108 CHECK_EQ(v8::Integer::New(isolate, 17), result2);
23112 TEST(EscapeableHandleScope) {
23113 HandleScope outer_scope(CcTest::isolate());
23114 LocalContext context;
23115 const int runs = 10;
23116 Local<String> values[runs];
23117 for (int i = 0; i < runs; i++) {
23118 v8::EscapableHandleScope inner_scope(CcTest::isolate());
23119 Local<String> value;
23120 if (i != 0) value = v8_str("escape value");
23121 values[i] = inner_scope.Escape(value);
23123 for (int i = 0; i < runs; i++) {
23124 Local<String> expected;
23126 CHECK_EQ(v8_str("escape value"), values[i]);
23128 CHECK(values[i].IsEmpty());
23134 static void SetterWhichExpectsThisAndHolderToDiffer(
23135 Local<String>, Local<Value>, const v8::PropertyCallbackInfo<void>& info) {
23136 CHECK(info.Holder() != info.This());
23140 TEST(Regress239669) {
23141 LocalContext context;
23142 v8::Isolate* isolate = context->GetIsolate();
23143 v8::HandleScope scope(isolate);
23144 Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
23145 templ->SetAccessor(v8_str("x"), 0, SetterWhichExpectsThisAndHolderToDiffer);
23146 context->Global()->Set(v8_str("P"), templ->NewInstance());
23151 "C1.prototype = P;"
23152 "for (var i = 0; i < 4; i++ ) {"
23158 class ApiCallOptimizationChecker {
23160 static Local<Object> data;
23161 static Local<Object> receiver;
23162 static Local<Object> holder;
23163 static Local<Object> callee;
23166 static void OptimizationCallback(
23167 const v8::FunctionCallbackInfo<v8::Value>& info) {
23168 CHECK(callee == info.Callee());
23169 CHECK(data == info.Data());
23170 CHECK(receiver == info.This());
23171 if (info.Length() == 1) {
23172 CHECK_EQ(v8_num(1), info[0]);
23174 CHECK(holder == info.Holder());
23176 info.GetReturnValue().Set(v8_str("returned"));
23180 enum SignatureType {
23182 kSignatureOnReceiver,
23183 kSignatureOnPrototype
23187 SignatureType signature_types[] =
23188 {kNoSignature, kSignatureOnReceiver, kSignatureOnPrototype};
23189 for (unsigned i = 0; i < arraysize(signature_types); i++) {
23190 SignatureType signature_type = signature_types[i];
23191 for (int j = 0; j < 2; j++) {
23192 bool global = j == 0;
23193 int key = signature_type +
23194 arraysize(signature_types) * (global ? 1 : 0);
23195 Run(signature_type, global, key);
23200 void Run(SignatureType signature_type, bool global, int key) {
23201 v8::Isolate* isolate = CcTest::isolate();
23202 v8::HandleScope scope(isolate);
23203 // Build a template for signature checks.
23204 Local<v8::ObjectTemplate> signature_template;
23205 Local<v8::Signature> signature;
23207 Local<v8::FunctionTemplate> parent_template =
23208 FunctionTemplate::New(isolate);
23209 parent_template->SetHiddenPrototype(true);
23210 Local<v8::FunctionTemplate> function_template
23211 = FunctionTemplate::New(isolate);
23212 function_template->Inherit(parent_template);
23213 switch (signature_type) {
23216 case kSignatureOnReceiver:
23217 signature = v8::Signature::New(isolate, function_template);
23219 case kSignatureOnPrototype:
23220 signature = v8::Signature::New(isolate, parent_template);
23223 signature_template = function_template->InstanceTemplate();
23225 // Global object must pass checks.
23226 Local<v8::Context> context =
23227 v8::Context::New(isolate, NULL, signature_template);
23228 v8::Context::Scope context_scope(context);
23229 // Install regular object that can pass signature checks.
23230 Local<Object> function_receiver = signature_template->NewInstance();
23231 context->Global()->Set(v8_str("function_receiver"), function_receiver);
23232 // Get the holder objects.
23233 Local<Object> inner_global =
23234 Local<Object>::Cast(context->Global()->GetPrototype());
23235 // Install functions on hidden prototype object if there is one.
23236 data = Object::New(isolate);
23237 Local<FunctionTemplate> function_template = FunctionTemplate::New(
23238 isolate, OptimizationCallback, data, signature);
23239 Local<Function> function = function_template->GetFunction();
23240 Local<Object> global_holder = inner_global;
23241 Local<Object> function_holder = function_receiver;
23242 if (signature_type == kSignatureOnPrototype) {
23243 function_holder = Local<Object>::Cast(function_holder->GetPrototype());
23244 global_holder = Local<Object>::Cast(global_holder->GetPrototype());
23246 global_holder->Set(v8_str("g_f"), function);
23247 global_holder->SetAccessorProperty(v8_str("g_acc"), function, function);
23248 function_holder->Set(v8_str("f"), function);
23249 function_holder->SetAccessorProperty(v8_str("acc"), function, function);
23250 // Initialize expected values.
23254 receiver = context->Global();
23255 holder = inner_global;
23257 holder = function_receiver;
23258 // If not using a signature, add something else to the prototype chain
23259 // to test the case that holder != receiver
23260 if (signature_type == kNoSignature) {
23261 receiver = Local<Object>::Cast(CompileRun(
23262 "var receiver_subclass = {};\n"
23263 "receiver_subclass.__proto__ = function_receiver;\n"
23264 "receiver_subclass"));
23266 receiver = Local<Object>::Cast(CompileRun(
23267 "var receiver_subclass = function_receiver;\n"
23268 "receiver_subclass"));
23271 // With no signature, the holder is not set.
23272 if (signature_type == kNoSignature) holder = receiver;
23273 // build wrap_function
23274 i::ScopedVector<char> wrap_function(200);
23278 "function wrap_f_%d() { var f = g_f; return f(); }\n"
23279 "function wrap_get_%d() { return this.g_acc; }\n"
23280 "function wrap_set_%d() { return this.g_acc = 1; }\n",
23285 "function wrap_f_%d() { return receiver_subclass.f(); }\n"
23286 "function wrap_get_%d() { return receiver_subclass.acc; }\n"
23287 "function wrap_set_%d() { return receiver_subclass.acc = 1; }\n",
23290 // build source string
23291 i::ScopedVector<char> source(1000);
23294 "%s\n" // wrap functions
23295 "function wrap_f() { return wrap_f_%d(); }\n"
23296 "function wrap_get() { return wrap_get_%d(); }\n"
23297 "function wrap_set() { return wrap_set_%d(); }\n"
23298 "check = function(returned) {\n"
23299 " if (returned !== 'returned') { throw returned; }\n"
23302 "check(wrap_f());\n"
23303 "check(wrap_f());\n"
23304 "%%OptimizeFunctionOnNextCall(wrap_f_%d);\n"
23305 "check(wrap_f());\n"
23307 "check(wrap_get());\n"
23308 "check(wrap_get());\n"
23309 "%%OptimizeFunctionOnNextCall(wrap_get_%d);\n"
23310 "check(wrap_get());\n"
23312 "check = function(returned) {\n"
23313 " if (returned !== 1) { throw returned; }\n"
23315 "check(wrap_set());\n"
23316 "check(wrap_set());\n"
23317 "%%OptimizeFunctionOnNextCall(wrap_set_%d);\n"
23318 "check(wrap_set());\n",
23319 wrap_function.start(), key, key, key, key, key, key);
23320 v8::TryCatch try_catch;
23321 CompileRun(source.start());
23322 DCHECK(!try_catch.HasCaught());
23323 CHECK_EQ(9, count);
23328 Local<Object> ApiCallOptimizationChecker::data;
23329 Local<Object> ApiCallOptimizationChecker::receiver;
23330 Local<Object> ApiCallOptimizationChecker::holder;
23331 Local<Object> ApiCallOptimizationChecker::callee;
23332 int ApiCallOptimizationChecker::count = 0;
23335 TEST(TestFunctionCallOptimization) {
23336 i::FLAG_allow_natives_syntax = true;
23337 ApiCallOptimizationChecker checker;
23342 static const char* last_event_message;
23343 static int last_event_status;
23344 void StoringEventLoggerCallback(const char* message, int status) {
23345 last_event_message = message;
23346 last_event_status = status;
23350 TEST(EventLogging) {
23351 v8::Isolate* isolate = CcTest::isolate();
23352 isolate->SetEventLogger(StoringEventLoggerCallback);
23353 v8::internal::HistogramTimer histogramTimer(
23354 "V8.Test", 0, 10000, 50,
23355 reinterpret_cast<v8::internal::Isolate*>(isolate));
23356 histogramTimer.Start();
23357 CHECK_EQ("V8.Test", last_event_message);
23358 CHECK_EQ(0, last_event_status);
23359 histogramTimer.Stop();
23360 CHECK_EQ("V8.Test", last_event_message);
23361 CHECK_EQ(1, last_event_status);
23366 LocalContext context;
23367 v8::Isolate* isolate = context->GetIsolate();
23368 v8::HandleScope scope(isolate);
23369 Handle<Object> global = context->Global();
23372 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
23373 Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
23374 Handle<v8::Promise> p = pr->GetPromise();
23375 Handle<v8::Promise> r = rr->GetPromise();
23376 CHECK_EQ(isolate, p->GetIsolate());
23378 // IsPromise predicate.
23379 CHECK(p->IsPromise());
23380 CHECK(r->IsPromise());
23381 Handle<Value> o = v8::Object::New(isolate);
23382 CHECK(!o->IsPromise());
23384 // Resolution and rejection.
23385 pr->Resolve(v8::Integer::New(isolate, 1));
23386 CHECK(p->IsPromise());
23387 rr->Reject(v8::Integer::New(isolate, 2));
23388 CHECK(r->IsPromise());
23390 // Chaining non-pending promises.
23394 "function f1(x) { x1 = x; return x+1 };\n"
23395 "function f2(x) { x2 = x; return x+1 };\n");
23396 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
23397 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
23400 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23401 isolate->RunMicrotasks();
23402 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23405 isolate->RunMicrotasks();
23406 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23409 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23410 isolate->RunMicrotasks();
23411 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
23414 isolate->RunMicrotasks();
23415 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23417 // Chaining pending promises.
23418 CompileRun("x1 = x2 = 0;");
23419 pr = v8::Promise::Resolver::New(isolate);
23420 rr = v8::Promise::Resolver::New(isolate);
23422 pr->GetPromise()->Chain(f1);
23423 rr->GetPromise()->Catch(f2);
23424 isolate->RunMicrotasks();
23425 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23426 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23428 pr->Resolve(v8::Integer::New(isolate, 1));
23429 rr->Reject(v8::Integer::New(isolate, 2));
23430 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23431 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23433 isolate->RunMicrotasks();
23434 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23435 CHECK_EQ(2, global->Get(v8_str("x2"))->Int32Value());
23438 CompileRun("x1 = x2 = 0;");
23439 pr = v8::Promise::Resolver::New(isolate);
23440 pr->GetPromise()->Chain(f1)->Chain(f2);
23441 pr->Resolve(v8::Integer::New(isolate, 3));
23442 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23443 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23444 isolate->RunMicrotasks();
23445 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23446 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23448 CompileRun("x1 = x2 = 0;");
23449 rr = v8::Promise::Resolver::New(isolate);
23450 rr->GetPromise()->Catch(f1)->Chain(f2);
23451 rr->Reject(v8::Integer::New(isolate, 3));
23452 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23453 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23454 isolate->RunMicrotasks();
23455 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23456 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23460 TEST(PromiseThen) {
23461 LocalContext context;
23462 v8::Isolate* isolate = context->GetIsolate();
23463 v8::HandleScope scope(isolate);
23464 Handle<Object> global = context->Global();
23467 Handle<v8::Promise::Resolver> pr = v8::Promise::Resolver::New(isolate);
23468 Handle<v8::Promise::Resolver> qr = v8::Promise::Resolver::New(isolate);
23469 Handle<v8::Promise> p = pr->GetPromise();
23470 Handle<v8::Promise> q = qr->GetPromise();
23472 CHECK(p->IsPromise());
23473 CHECK(q->IsPromise());
23475 pr->Resolve(v8::Integer::New(isolate, 1));
23478 // Chaining non-pending promises.
23482 "function f1(x) { x1 = x; return x+1 };\n"
23483 "function f2(x) { x2 = x; return x+1 };\n");
23484 Handle<Function> f1 = Handle<Function>::Cast(global->Get(v8_str("f1")));
23485 Handle<Function> f2 = Handle<Function>::Cast(global->Get(v8_str("f2")));
23489 CHECK(global->Get(v8_str("x1"))->IsNumber());
23490 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23491 isolate->RunMicrotasks();
23492 CHECK(!global->Get(v8_str("x1"))->IsNumber());
23493 CHECK_EQ(p, global->Get(v8_str("x1")));
23496 CompileRun("x1 = x2 = 0;");
23498 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23499 isolate->RunMicrotasks();
23500 CHECK_EQ(1, global->Get(v8_str("x1"))->Int32Value());
23503 CompileRun("x1 = x2 = 0;");
23504 pr = v8::Promise::Resolver::New(isolate);
23505 qr = v8::Promise::Resolver::New(isolate);
23508 qr->GetPromise()->Then(f1)->Then(f2);
23510 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23511 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23512 isolate->RunMicrotasks();
23513 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23514 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23516 pr->Resolve(v8::Integer::New(isolate, 3));
23518 CHECK_EQ(0, global->Get(v8_str("x1"))->Int32Value());
23519 CHECK_EQ(0, global->Get(v8_str("x2"))->Int32Value());
23520 isolate->RunMicrotasks();
23521 CHECK_EQ(3, global->Get(v8_str("x1"))->Int32Value());
23522 CHECK_EQ(4, global->Get(v8_str("x2"))->Int32Value());
23526 TEST(DisallowJavascriptExecutionScope) {
23527 LocalContext context;
23528 v8::Isolate* isolate = context->GetIsolate();
23529 v8::HandleScope scope(isolate);
23530 v8::Isolate::DisallowJavascriptExecutionScope no_js(
23531 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23536 TEST(AllowJavascriptExecutionScope) {
23537 LocalContext context;
23538 v8::Isolate* isolate = context->GetIsolate();
23539 v8::HandleScope scope(isolate);
23540 v8::Isolate::DisallowJavascriptExecutionScope no_js(
23541 isolate, v8::Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
23542 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23543 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23544 { v8::Isolate::AllowJavascriptExecutionScope yes_js(isolate);
23550 TEST(ThrowOnJavascriptExecution) {
23551 LocalContext context;
23552 v8::Isolate* isolate = context->GetIsolate();
23553 v8::HandleScope scope(isolate);
23554 v8::TryCatch try_catch;
23555 v8::Isolate::DisallowJavascriptExecutionScope throw_js(
23556 isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
23558 CHECK(try_catch.HasCaught());
23562 TEST(Regress354123) {
23563 LocalContext current;
23564 v8::Isolate* isolate = current->GetIsolate();
23565 v8::HandleScope scope(isolate);
23567 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
23568 templ->SetAccessCheckCallbacks(NamedAccessCounter, IndexedAccessCounter);
23569 current->Global()->Set(v8_str("friend"), templ->NewInstance());
23571 // Test access using __proto__ from the prototype chain.
23572 named_access_count = 0;
23573 CompileRun("friend.__proto__ = {};");
23574 CHECK_EQ(2, named_access_count);
23575 CompileRun("friend.__proto__;");
23576 CHECK_EQ(4, named_access_count);
23578 // Test access using __proto__ as a hijacked function (A).
23579 named_access_count = 0;
23580 CompileRun("var p = Object.prototype;"
23581 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').set;"
23582 "f.call(friend, {});");
23583 CHECK_EQ(1, named_access_count);
23584 CompileRun("var p = Object.prototype;"
23585 "var f = Object.getOwnPropertyDescriptor(p, '__proto__').get;"
23586 "f.call(friend);");
23587 CHECK_EQ(2, named_access_count);
23589 // Test access using __proto__ as a hijacked function (B).
23590 named_access_count = 0;
23591 CompileRun("var f = Object.prototype.__lookupSetter__('__proto__');"
23592 "f.call(friend, {});");
23593 CHECK_EQ(1, named_access_count);
23594 CompileRun("var f = Object.prototype.__lookupGetter__('__proto__');"
23595 "f.call(friend);");
23596 CHECK_EQ(2, named_access_count);
23598 // Test access using Object.setPrototypeOf reflective method.
23599 named_access_count = 0;
23600 CompileRun("Object.setPrototypeOf(friend, {});");
23601 CHECK_EQ(1, named_access_count);
23602 CompileRun("Object.getPrototypeOf(friend);");
23603 CHECK_EQ(2, named_access_count);
23607 TEST(CaptureStackTraceForStackOverflow) {
23608 v8::internal::FLAG_stack_size = 150;
23609 LocalContext current;
23610 v8::Isolate* isolate = current->GetIsolate();
23611 v8::HandleScope scope(isolate);
23612 V8::SetCaptureStackTraceForUncaughtExceptions(
23613 true, 10, v8::StackTrace::kDetailed);
23614 v8::TryCatch try_catch;
23615 CompileRun("(function f(x) { f(x+1); })(0)");
23616 CHECK(try_catch.HasCaught());
23620 TEST(ScriptNameAndLineNumber) {
23622 v8::Isolate* isolate = env->GetIsolate();
23623 v8::HandleScope scope(isolate);
23624 const char* url = "http://www.foo.com/foo.js";
23625 v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
23626 v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
23627 Local<Script> script = v8::ScriptCompiler::Compile(
23628 isolate, &script_source);
23629 Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
23630 CHECK(!script_name.IsEmpty());
23631 CHECK(script_name->IsString());
23632 String::Utf8Value utf8_name(script_name);
23633 CHECK_EQ(url, *utf8_name);
23634 int line_number = script->GetUnboundScript()->GetLineNumber(0);
23635 CHECK_EQ(13, line_number);
23639 void SourceURLHelper(const char* source, const char* expected_source_url,
23640 const char* expected_source_mapping_url) {
23641 Local<Script> script = v8_compile(source);
23642 if (expected_source_url != NULL) {
23643 v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
23644 CHECK_EQ(expected_source_url, *url);
23646 CHECK(script->GetUnboundScript()->GetSourceURL()->IsUndefined());
23648 if (expected_source_mapping_url != NULL) {
23649 v8::String::Utf8Value url(
23650 script->GetUnboundScript()->GetSourceMappingURL());
23651 CHECK_EQ(expected_source_mapping_url, *url);
23653 CHECK(script->GetUnboundScript()->GetSourceMappingURL()->IsUndefined());
23658 TEST(ScriptSourceURLAndSourceMappingURL) {
23660 v8::Isolate* isolate = env->GetIsolate();
23661 v8::HandleScope scope(isolate);
23662 SourceURLHelper("function foo() {}\n"
23663 "//# sourceURL=bar1.js\n", "bar1.js", NULL);
23664 SourceURLHelper("function foo() {}\n"
23665 "//# sourceMappingURL=bar2.js\n", NULL, "bar2.js");
23667 // Both sourceURL and sourceMappingURL.
23668 SourceURLHelper("function foo() {}\n"
23669 "//# sourceURL=bar3.js\n"
23670 "//# sourceMappingURL=bar4.js\n", "bar3.js", "bar4.js");
23672 // Two source URLs; the first one is ignored.
23673 SourceURLHelper("function foo() {}\n"
23674 "//# sourceURL=ignoreme.js\n"
23675 "//# sourceURL=bar5.js\n", "bar5.js", NULL);
23676 SourceURLHelper("function foo() {}\n"
23677 "//# sourceMappingURL=ignoreme.js\n"
23678 "//# sourceMappingURL=bar6.js\n", NULL, "bar6.js");
23680 // SourceURL or sourceMappingURL in the middle of the script.
23681 SourceURLHelper("function foo() {}\n"
23682 "//# sourceURL=bar7.js\n"
23683 "function baz() {}\n", "bar7.js", NULL);
23684 SourceURLHelper("function foo() {}\n"
23685 "//# sourceMappingURL=bar8.js\n"
23686 "function baz() {}\n", NULL, "bar8.js");
23688 // Too much whitespace.
23689 SourceURLHelper("function foo() {}\n"
23690 "//# sourceURL=bar9.js\n"
23691 "//# sourceMappingURL=bar10.js\n", NULL, NULL);
23692 SourceURLHelper("function foo() {}\n"
23693 "//# sourceURL =bar11.js\n"
23694 "//# sourceMappingURL =bar12.js\n", NULL, NULL);
23696 // Disallowed characters in value.
23697 SourceURLHelper("function foo() {}\n"
23698 "//# sourceURL=bar13 .js \n"
23699 "//# sourceMappingURL=bar14 .js \n",
23701 SourceURLHelper("function foo() {}\n"
23702 "//# sourceURL=bar15\t.js \n"
23703 "//# sourceMappingURL=bar16\t.js \n",
23705 SourceURLHelper("function foo() {}\n"
23706 "//# sourceURL=bar17'.js \n"
23707 "//# sourceMappingURL=bar18'.js \n",
23709 SourceURLHelper("function foo() {}\n"
23710 "//# sourceURL=bar19\".js \n"
23711 "//# sourceMappingURL=bar20\".js \n",
23714 // Not too much whitespace.
23715 SourceURLHelper("function foo() {}\n"
23716 "//# sourceURL= bar21.js \n"
23717 "//# sourceMappingURL= bar22.js \n", "bar21.js", "bar22.js");
23721 TEST(GetOwnPropertyDescriptor) {
23723 v8::Isolate* isolate = env->GetIsolate();
23724 v8::HandleScope scope(isolate);
23726 "var x = { value : 13};"
23727 "Object.defineProperty(x, 'p0', {value : 12});"
23728 "Object.defineProperty(x, 'p1', {"
23729 " set : function(value) { this.value = value; },"
23730 " get : function() { return this.value; },"
23732 Local<Object> x = Local<Object>::Cast(env->Global()->Get(v8_str("x")));
23733 Local<Value> desc = x->GetOwnPropertyDescriptor(v8_str("no_prop"));
23734 CHECK(desc->IsUndefined());
23735 desc = x->GetOwnPropertyDescriptor(v8_str("p0"));
23736 CHECK_EQ(v8_num(12), Local<Object>::Cast(desc)->Get(v8_str("value")));
23737 desc = x->GetOwnPropertyDescriptor(v8_str("p1"));
23738 Local<Function> set =
23739 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("set")));
23740 Local<Function> get =
23741 Local<Function>::Cast(Local<Object>::Cast(desc)->Get(v8_str("get")));
23742 CHECK_EQ(v8_num(13), get->Call(x, 0, NULL));
23743 Handle<Value> args[] = { v8_num(14) };
23744 set->Call(x, 1, args);
23745 CHECK_EQ(v8_num(14), get->Call(x, 0, NULL));
23749 TEST(Regress411877) {
23750 v8::Isolate* isolate = CcTest::isolate();
23751 v8::HandleScope handle_scope(isolate);
23752 v8::Handle<v8::ObjectTemplate> object_template =
23753 v8::ObjectTemplate::New(isolate);
23754 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23755 IndexedAccessCounter);
23757 v8::Handle<Context> context = Context::New(isolate);
23758 v8::Context::Scope context_scope(context);
23760 context->Global()->Set(v8_str("o"), object_template->NewInstance());
23761 CompileRun("Object.getOwnPropertyNames(o)");
23765 TEST(GetHiddenPropertyTableAfterAccessCheck) {
23766 v8::Isolate* isolate = CcTest::isolate();
23767 v8::HandleScope handle_scope(isolate);
23768 v8::Handle<v8::ObjectTemplate> object_template =
23769 v8::ObjectTemplate::New(isolate);
23770 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23771 IndexedAccessCounter);
23773 v8::Handle<Context> context = Context::New(isolate);
23774 v8::Context::Scope context_scope(context);
23776 v8::Handle<v8::Object> obj = object_template->NewInstance();
23777 obj->Set(v8_str("key"), v8_str("value"));
23778 obj->Delete(v8_str("key"));
23780 obj->SetHiddenValue(v8_str("hidden key 2"), v8_str("hidden value 2"));
23784 TEST(Regress411793) {
23785 v8::Isolate* isolate = CcTest::isolate();
23786 v8::HandleScope handle_scope(isolate);
23787 v8::Handle<v8::ObjectTemplate> object_template =
23788 v8::ObjectTemplate::New(isolate);
23789 object_template->SetAccessCheckCallbacks(NamedAccessCounter,
23790 IndexedAccessCounter);
23792 v8::Handle<Context> context = Context::New(isolate);
23793 v8::Context::Scope context_scope(context);
23795 context->Global()->Set(v8_str("o"), object_template->NewInstance());
23797 "Object.defineProperty(o, 'key', "
23798 " { get: function() {}, set: function() {} });");
23801 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream {
23803 explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {}
23805 virtual size_t GetMoreData(const uint8_t** src) {
23806 // Unlike in real use cases, this function will never block.
23807 if (chunks_[index_] == NULL) {
23810 // Copy the data, since the caller takes ownership of it.
23811 size_t len = strlen(chunks_[index_]);
23812 // We don't need to zero-terminate since we return the length.
23813 uint8_t* copy = new uint8_t[len];
23814 memcpy(copy, chunks_[index_], len);
23820 // Helper for constructing a string from chunks (the compilation needs it
23822 static char* FullSourceString(const char** chunks) {
23823 size_t total_len = 0;
23824 for (size_t i = 0; chunks[i] != NULL; ++i) {
23825 total_len += strlen(chunks[i]);
23827 char* full_string = new char[total_len + 1];
23829 for (size_t i = 0; chunks[i] != NULL; ++i) {
23830 size_t len = strlen(chunks[i]);
23831 memcpy(full_string + offset, chunks[i], len);
23834 full_string[total_len] = 0;
23835 return full_string;
23839 const char** chunks_;
23844 // Helper function for running streaming tests.
23845 void RunStreamingTest(const char** chunks,
23846 v8::ScriptCompiler::StreamedSource::Encoding encoding =
23847 v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23848 bool expected_success = true) {
23850 v8::Isolate* isolate = env->GetIsolate();
23851 v8::HandleScope scope(isolate);
23852 v8::TryCatch try_catch;
23854 v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks),
23856 v8::ScriptCompiler::ScriptStreamingTask* task =
23857 v8::ScriptCompiler::StartStreamingScript(isolate, &source);
23859 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
23860 // task here in the main thread.
23864 v8::ScriptOrigin origin(v8_str("http://foo.com"));
23865 char* full_source = TestSourceStream::FullSourceString(chunks);
23867 // The possible errors are only produced while compiling.
23868 CHECK_EQ(false, try_catch.HasCaught());
23870 v8::Handle<Script> script = v8::ScriptCompiler::Compile(
23871 isolate, &source, v8_str(full_source), origin);
23872 if (expected_success) {
23873 CHECK(!script.IsEmpty());
23874 v8::Handle<Value> result(script->Run());
23875 // All scripts are supposed to return the fixed value 13 when ran.
23876 CHECK_EQ(13, result->Int32Value());
23878 CHECK(script.IsEmpty());
23879 CHECK(try_catch.HasCaught());
23881 delete[] full_source;
23885 TEST(StreamingSimpleScript) {
23886 // This script is unrealistically small, since no one chunk is enough to fill
23887 // the backing buffer of Scanner, let alone overflow it.
23888 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
23890 RunStreamingTest(chunks);
23894 TEST(StreamingBiggerScript) {
23895 const char* chunk1 =
23896 "function foo() {\n"
23897 " // Make this chunk sufficiently long so that it will overflow the\n"
23898 " // backing buffer of the Scanner.\n"
23900 " var result = 0;\n"
23901 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23903 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23905 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23907 " for (i = 0; i < 13; ++i) { result = result + 1; }\n"
23908 " return result;\n"
23910 const char* chunks[] = {chunk1, "foo(); ", NULL};
23911 RunStreamingTest(chunks);
23915 TEST(StreamingScriptWithParseError) {
23916 // Test that parse errors from streamed scripts are propagated correctly.
23919 " // This will result in a parse error.\n"
23920 " var if else then foo";
23921 char chunk2[] = " 13\n";
23922 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23924 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE,
23927 // Test that the next script succeeds normally.
23930 " // This will be parsed successfully.\n"
23931 " function foo() { return ";
23932 char chunk2[] = " 13; }\n";
23933 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23935 RunStreamingTest(chunks);
23940 TEST(StreamingUtf8Script) {
23941 // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
23943 const char* chunk1 =
23944 "function foo() {\n"
23945 " // This function will contain an UTF-8 character which is not in\n"
23947 " var foob\xec\x92\x81r = 13;\n"
23948 " return foob\xec\x92\x81r;\n"
23950 const char* chunks[] = {chunk1, "foo(); ", NULL};
23951 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23955 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) {
23956 // A sanity check to prove that the approach of splitting UTF-8
23957 // characters is correct. Here is an UTF-8 character which will take three
23959 const char* reference = "\xec\x92\x81";
23960 CHECK(3u == strlen(reference)); // NOLINT - no CHECK_EQ for unsigned.
23963 "function foo() {\n"
23964 " // This function will contain an UTF-8 character which is not in\n"
23969 " return foob\xec\x92\x81r;\n"
23971 for (int i = 0; i < 3; ++i) {
23972 chunk2[i] = reference[i];
23974 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23975 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
23979 TEST(StreamingUtf8ScriptWithSplitCharacters) {
23980 // Stream data where a multi-byte UTF-8 character is split between two data
23982 const char* reference = "\xec\x92\x81";
23984 "function foo() {\n"
23985 " // This function will contain an UTF-8 character which is not in\n"
23990 " return foob\xec\x92\x81r;\n"
23992 chunk1[strlen(chunk1) - 1] = reference[0];
23993 chunk2[0] = reference[1];
23994 chunk2[1] = reference[2];
23995 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
23996 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24000 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) {
24001 // Tests edge cases which should still be decoded correctly.
24003 // Case 1: a chunk contains only bytes for a split character (and no other
24004 // data). This kind of a chunk would be exceptionally small, but we should
24005 // still decode it correctly.
24006 const char* reference = "\xec\x92\x81";
24007 // The small chunk is at the beginning of the split character
24010 "function foo() {\n"
24011 " // This function will contain an UTF-8 character which is not in\n"
24014 char chunk2[] = "XX";
24017 " return foob\xec\x92\x81r;\n"
24019 chunk2[0] = reference[0];
24020 chunk2[1] = reference[1];
24021 chunk3[0] = reference[2];
24022 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24023 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24025 // The small chunk is at the end of a character
24028 "function foo() {\n"
24029 " // This function will contain an UTF-8 character which is not in\n"
24032 char chunk2[] = "XX";
24035 " return foob\xec\x92\x81r;\n"
24037 chunk1[strlen(chunk1) - 1] = reference[0];
24038 chunk2[0] = reference[1];
24039 chunk2[1] = reference[2];
24040 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24041 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24043 // Case 2: the script ends with a multi-byte character. Make sure that it's
24044 // decoded correctly and not just ignored.
24047 "var foob\xec\x92\x81 = 13;\n"
24048 "foob\xec\x92\x81";
24049 const char* chunks[] = {chunk1, NULL};
24050 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24055 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) {
24056 // Test cases where a UTF-8 character is split over several chunks. Those
24057 // cases are not supported (the embedder should give the data in big enough
24058 // chunks), but we shouldn't crash, just produce a parse error.
24059 const char* reference = "\xec\x92\x81";
24061 "function foo() {\n"
24062 " // This function will contain an UTF-8 character which is not in\n"
24065 char chunk2[] = "X";
24068 " return foob\xec\x92\x81r;\n"
24070 chunk1[strlen(chunk1) - 1] = reference[0];
24071 chunk2[0] = reference[1];
24072 chunk3[0] = reference[2];
24073 const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL};
24075 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24079 TEST(StreamingProducesParserCache) {
24080 i::FLAG_min_preparse_length = 0;
24081 const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ",
24085 v8::Isolate* isolate = env->GetIsolate();
24086 v8::HandleScope scope(isolate);
24088 v8::ScriptCompiler::StreamedSource source(
24089 new TestSourceStream(chunks),
24090 v8::ScriptCompiler::StreamedSource::ONE_BYTE);
24091 v8::ScriptCompiler::ScriptStreamingTask* task =
24092 v8::ScriptCompiler::StartStreamingScript(
24093 isolate, &source, v8::ScriptCompiler::kProduceParserCache);
24095 // TestSourceStream::GetMoreData won't block, so it's OK to just run the
24096 // task here in the main thread.
24100 const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
24101 CHECK(cached_data != NULL);
24102 CHECK(cached_data->data != NULL);
24103 CHECK_GT(cached_data->length, 0);
24107 TEST(StreamingScriptWithInvalidUtf8) {
24108 // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
24109 // chunk don't produce a crash.
24110 const char* reference = "\xec\x92\x81\x80\x80";
24112 "function foo() {\n"
24113 " // This function will contain an UTF-8 character which is not in\n"
24115 " var foobXXXXX"; // Too many bytes which look like incomplete chars!
24118 " return foob\xec\x92\x81\x80\x80r;\n"
24120 for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
24122 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24123 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
24127 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
24128 // Regression test: Stream data where there are several multi-byte UTF-8
24129 // characters in a sequence and one of them is split between two data chunks.
24130 const char* reference = "\xec\x92\x81";
24132 "function foo() {\n"
24133 " // This function will contain an UTF-8 character which is not in\n"
24135 " var foob\xec\x92\x81X";
24138 " return foob\xec\x92\x81\xec\x92\x81r;\n"
24140 chunk1[strlen(chunk1) - 1] = reference[0];
24141 chunk2[0] = reference[1];
24142 chunk2[1] = reference[2];
24143 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24144 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
24148 TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
24149 // Another regression test, similar to the previous one. The difference is
24150 // that the split character is not the last one in the sequence.
24151 const char* reference = "\xec\x92\x81";
24153 "function foo() {\n"
24154 " // This function will contain an UTF-8 character which is not in\n"
24158 "XX\xec\x92\x81r = 13;\n"
24159 " return foob\xec\x92\x81\xec\x92\x81r;\n"
24161 chunk1[strlen(chunk1) - 1] = reference[0];
24162 chunk2[0] = reference[1];
24163 chunk2[1] = reference[2];
24164 const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
24165 RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);